쿠버네티스를 운영하다가 트래픽이 어느정도 된 이후에 간헐적으로 DNS Resolve timedout가 발생한 적이 있는데 관련해서 쿠버네티스에서 CoreDNS와 DNS 쿼리 관련하여 분석해보았다. 애플리케이션에서 찍힌 에러 로그는 다음과 유사하다.
Failed to resolve 'api.test.com' [A(1)] after 2 queries
CoreDNS와 서비스간 통신
CoreDNS는 쿠버네티스에서 클러스터에서 DNS 서버역할을 하는 애드온이다. 클러스터 내에서 서비스를 생성하면 서비스에 대한 DNS 레코드가 생성되는데 이러한 DNS 레코드는 CoreDNS에서 관리한다.
예를 들어, saga 네임스페이스의 account-service가 생성되면 account-service.saga.svc.cluster.local 이라는 DNS가 생성된다.
그리고 특정 파드에서 account-service.saga.svc.cluster.local 으로 통신이 가능한데, 서비스와 통신을 하기 전에 CoreDNS를 통해 DNS에 대한 ClusterIP를 획득한 다음 IP로 통신하게 된다.

특정 파드에서 서비스로 통신할 때 과정을 자세히 보면 다음과 같다.

- CoreDNS로 DNS lookup을 하여 서비스의 ClusterIP를 획득한다.
- 전달받은 ClusterIP를 사용하여 HTTP 통신을 한다. kube-proxy가 iptables으로 되어있다면, 각 노드에 깔려있는 ClusterIP에 대한 DNAT에 의해 랜덤으로 특정 파드 IP로 목적지가 변경되어 특정 파드로 전달된다. (로드밸런싱)
CoreDNS 메트릭 확인
그런데 왜 간헐적으로 DNS Resolve timedout가 발생한걸까? 일단 프로메테우스로 수집한 CoreDNS 관련 메트릭으로 대시보드를 만들었는데, 응답과 관련된 메트릭을 확인해보았다.

sum(rate(coredns_dns_responses_total[1m])) by (service, rcode)
메트릭을 보면 NXDOMAIN이 75%정도이고, NOERROR가 25%정도 정도로 분포가 되어있는 것으로 확인이 되었다. 그런데 NXDOMAIN이 NOERROR에 비해 3배 더 많은데, 실제로 DNS 관련 에러는 엄청 간헐적으로 나왔었다. 실제로는 DNS 쿼리가 잘 되는데도 불구하고 NXDOMAIN이 왜 많이 나오는걸까?
ndots와 search options
일단 아무 파드로 접속해서 /etc/resolv.conf를 확인해보자.

여기서는 인스턴스의 DNS 관련 설정이 담겨있다.
nameserver는 DNS 쿼리를 질의할 서버 IP가 설정되어있는데 기본적으로 CoreDNS로 되어있다.ndots옵션은 질의할 도메인의 점 갯수가 ndots 보다 적다면 search 도메인을 사용하여 질의를 한다.search는 ndots보다 적은 갯수의 점이 있는 도메인을 질의하는 경우, search에 있는 문자열 순서대로 도메인 뒤에 붙여서 DNS 질의를 시도한다.
예를 들어, 파드에서 account-service.saga.svc.cluster.local 으로 DNS 질의를 하는 경우, 여기에 해당하는 점이 4개 있으므로 ndots보다 작기 때문에 search 옵션에 의해 문자열 순서대로 도메인 뒤에 붙여서 DNS를 질의한다.
보다 정확한 동작을 이해하기 위해 tcpdump로 DNS 질의 과정을 확인할 수 있다.
tcpdump -i any port 53

account-service.saga.svc.cluster.local도메인은 점이 4개이다 (<5). 따라서 search 옵션이 적용된다.- search 옵션에 의해
saga.svc.cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - search 옵션에 의해
svc.cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - search 옵션에 의해
cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - 마지막으로 요청한 도메인 뒤에 . 을 붙여서 질의 => 질의 성공
즉, account-service.saga.svc.cluster.local으로 통신하면 3번 실패, 1번 성공하게 된다. 이전에 메트릭에서 집계된 결과와 일맥상 통한다.
ndots:4로 변경해보기
account-service.saga.svc.cluster.local 이라는 도메인은 점이 4개 있다. 그리고 ndots=5 로 옵션이 설정되어 있기 때문에 search 옵션을 적용하고, 여러개의 NXDOMAIN이 발생한다. 그렇다면 ndots을 4 이하로 줄여서 search 옵션을 적용하지 않도록 하면 NXDOMAIN 문제를 해결할 수 있을 것으로 보인다.
파드의 /etc/resolv.conf 에서 ndots:4로 옵션을 수정해보자. 그 후 account-service.saga.svc.cluster.local 으로 DNS를 요청하면 NXDOMAIN 에러가 발생하지 않는 것을 알 수 있다.

account-service.saga.svc.cluster.local도메인은 점이 4개이다 (<=4). 따라서 search 옵션이 적용되지 않고 바로 DNS 요청을 한다.
점 개수가 4 미만인 도메인은?
하지만 서비스의 FQDN 외에도 여러가지 고려 사항들이 있다. 쿠버네티스 내부 서비스와 통신하는 것 외에도 외부 서비스와 통신하는 경우도 많기 때문이다.
- 서비스 FQDN
- 일부가 생략된 서비스 DNS
- 외부 도메인 (ndots=2, 3 등)
이 중에 서비스 FQDN은 테스트가 완료되었으니 나머지 케이스에 대해서도 확인을 해보자.
일부가 생략된 서비스 DNS
쿠버네티스에서는 네임스페이스 메커니즘이 있는데, 같은 네임스페이스에서는 {service-name} 으로도 통신이 가능하다. 그리고 같은 클러스터 내 다른 네임스페이스 간 통신으로는 {service-name}.{namespace} 로도 통신이 가능하다. 이 경우를 한번 테스트해보자.
먼저 {service-name} 으로 통신 했을 경우이다.

이 때는 점 갯수가 ndots보다 적기 때문에 search 옵션이 적용된다. search 옵션에서 맨 첫번째 문자열은 {namespace}.svc.cluster.local 이기 때문에 해당 도메인이 뒤에 붙어서 나온 최종 결과가 {service-name}.{namespace}.svc.cluster.local 으로 FQDN과 동일하다.
두 번째로는 {service-name}.{namespace} 으로 통신 했을 경우이다.

이 때도 점 갯수가 ndots보다 적기 때문에 search 옵션이 적용된다.
search 옵션에서 맨 첫번째 문자열은 {namespace}.svc.cluster.local 인데, 해당 도메인이 뒤에 붙어서 나온 최종 결과가 {service-name}.{namespace}.{namespace}.svc.cluster.local 이며, 해당 도메인은 없는 도메인이라서 NXDOMAIN이 붙는다.
search 옵션에서 두번째 문자열은 svc.cluster.local 이며 해당 도메인이 뒤에 붙어서 나온 최종 결과가 {service-name}.{namespace}.svc.cluster.local 으로 FQDN과 동일하다. 이 때 질의가 성공하게 된다.
최종적으로 ndots:4로 적용하면 일부가 생략된 서비스 DNS는 다른 네임스페이스 내 서비스와 통신할 때는 1번의 NXDOMAIN이 발생한다. NXDOMAIN을 없애려면 다른 네임스페이스간 통신을 할 때는 FQDN으로 통신하면 된다.
외부 도메인
점 개수가 2개인 외부 도메인과 통신한다면 어떻게 될까? 예를 들어 www.google.com 에 통신한다면 다음과 같은 결과를 얻을 수 있다. (점 개수가 1개인 google.com, 점 개수가 3개인 www.google.co.kr 모두 같은 결과이므로 생략)

www.google.com도메인은 점이 2개이다 (<4). 따라서 search 옵션이 적용된다.- search 옵션에 의해
saga.svc.cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - search 옵션에 의해
svc.cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - search 옵션에 의해
cluster.local을 도메인 뒤에 붙여서 질의를 한다. => 해당하는 도메인이 레코드에 없어서 NXDOMAIN 에러가 발생 - 마지막으로 요청한 도메인 뒤에 . 을 붙여서 질의 => 질의 성공
총 3번의 NXDOMAIN이 발생하게 된다. 외부 도메인은 내부 서비스 도메인과 다르게 많은 NXDOMAIN이 발생하게 된다.
도메인에 대해 search 옵션을 타지 않도록 강제하는 방법이 있는데, 도메인 뒤에 .을 마지막으로 붙여서 루트 도메인을 명시하는 방법이 있다. ndots=4로 지정한 경우 이 옵션을 통해 외부 도메인에 대해 많은 NXDOMAIN을 방지할 수 있기는 하다.
curl https://www.google.com.
하지만 쿠버네티스 클러스터의 규모가 클수록, 조직 수가 많을수록 모든 도메인 뒤에 .이 붙여져있는지 확인하는 것은 상당히 어려울 뿐 아니라 익숙하지 않은 방법이기 때문에 대부분은 . 을 붙여서 통신하지 않을 것이다.
결론은 ndots:4인 경우 완전히 NXDOMAIN이 발생하지 않는 조건은 다음과 같다.
- 서비스 FQDN
- 같은 네임스페이스 내의 생략된 서비스 DNS
ndots:2로 변경해보기
위와 같은 이슈로 ndots:4는 외부 도메인에 대해서는 해결이 안된다. 그래서 보편적으로 많이 사용하는 방식은 ndots:2 로 설정하는 방식이다. 이 방식을 적용하면 대부분의 경우는 완전히 NXDOMAIN이 발생하지 않는다.
- 서비스 FQDN
- 같은 네임스페이스 내의 생략된 서비스 DNS
- 외부 도메인 (ndots=2, 3 등)

- 보라색 박스를 보면 같은 네임스페이스 내 서비스 DNS는 NXDOMAIN 없이 정상 쿼리된다.
- 파란색 박스를 보면 다른 네임스페이스 내 서비스 DNS는 NXDOMAIN 없이 정상 쿼리된다.
- 노란색 박스를 보면 서비스 FQDN는 NXDOMAIN 없이 정상 쿼리된다.
- 초록색 박스를 보면 dots=2(이상)인 외부 도메인은 NXDOMAIN 없이 정상 쿼리된다.
- 주황색 박스를 보면 dots=1인 외부 도메인은 search 옵션을 타기 때문에 3번의 NXDOMAIN 이 발생한다.
- 빨간색 박스를 보면
{service-name}.{namespace}.svc로 호출하면 search 옵션을 타지 않으며, DNS 질의에 실패하게 된다.
테스트 결과를 보면 ndots:2가 만능은 아니라는 것을 알 수 있다. ndots:2로 지정하는 경우에는 다음의 경우가 커버되지 않는다.
- 다른 네임스페이스 내의 생략된 서비스 DNS (NXDOMAIN 1회 발생)
- dot=1인 외부 DNS (NXDOMAIN 3회 발생)
{service-name}.{namespace}.svc,{pod-ip}.{namespace}.pod(DNS 조회 실패)
따라서 ndots:2로 설정할 떄는 {service-name}.{namespace}.svc 또는 {pod-ip}.{namespace}.pod 로 호출하는 로직이 있는지는 반드시 파악해야 한다.
- NXDOMAIN이 발생하는 경우에는 그래도 결국 DNS 질의는 가능하기 때문에 ndots 변경 후에도 서비스 영향은 없다.
- 하지만
{service-name}.{namespace}.svc,{pod-ip}.{namespace}.pod의 경우 ndots:5 -> 2로 변경하면 반드시 에러가 발생한다 - 다른 네임스페이스 내의 생략된 서비스 DNS,
{service-name}.{namespace}.svc,{pod-ip}.{namespace}.pod의 경우 FQDN으로 변경, dot=1인 외부 DNS는 .을 추가하면 NXDOMAIN 및 질의 실패를 피할 수 있다.
ndots 설정 변경하기
파드 내에서 /etc/resolv.conf 를 변경하더라도 파드가 재배포되면 다시 초기화된다. 따라서 영구적으로 ndots 설정을 저정할 필요가 있는데, 이를 영구저장하기 위해서는 파드의 dnsConfig 필드를 다음과 같이 변경하면 된다.
spec:
dnsConfig:
options:
- name: ndots
value: "2"'DevOps > Kubernetes' 카테고리의 다른 글
| Kubernetes Custom Resource와 Custom Controller 소개 (0) | 2025.10.13 |
|---|---|
| Kubernetes Node ContainerGCFailed 트러블슈팅 (0) | 2025.09.30 |
| 쿠버네티스에서의 고가용성 (High Availability) (1) | 2025.01.26 |
| Kubernetes HPA (파드 오토스케일링) [2] - 동작 제어 (2) | 2025.01.05 |
| Kubernetes HPA (파드 오토스케일링) [1] - 기초 (2) | 2025.01.05 |
댓글