{"id":"IL-0083","org":"Adevinta","date":"2023-06-13","docs":["https://qasim-sarfraz.medium.com/dns-caching-gone-wrong-a329dc00452e"],"title":{"en":"Intermittent 5xx errors in a multi-tenant Kubernetes cluster came from internal DNS: the node-local dnsmasq hit its 150 concurrent query limit, did not cache cluster.local answers, and ndots search lookups flooded CoreDNS","ko":"멀티 테넌트 쿠버네티스 클러스터에서 노드 로컬 dnsmasq 가 동시 질의 한도에 걸리고 cluster.local 응답을 캐시하지 못한 데다 ndots 검색 도메인 질의가 CoreDNS 로 몰려, 서비스 간 호출이 간헐적인 5xx 를 냈다."},"domain":["kubernetes","networking"],"impact":{"scope":"Intermittent HTTP 5xx errors for services in one SCHIP Kubernetes cluster, mostly one proxy application; DNS latency degraded in two or three other large clusters","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The DNS Latency SLI had shown the problem long before anyone looked at it. An SLO only protects you when its SLIs are trusted and a drop is investigated.\n\nThe investigation took a month partly because several on-call groups worked on it separately, without one place for observations and hypotheses, and sometimes chased hypotheses already discarded. Disprove one hypothesis before starting the next, and collect data the metrics system lacks: DNStop showed the garbage lookups that no dashboard did.\n\nWith ndots:5, short service names multiply DNS traffic; a node-local cache only helps if it can cache the cluster DNS answers at all.","ko":"SLO 를 보기 좋은 지표로만 두지 말고 안전장치로 써야 한다. 이번에는 나빠진 DNS Latency SLI 를 오래 무시한 탓에 원인을 늦게 찾았다. SLO 를 안전장치로 쓰려면 믿을 수 있는 SLI 가 먼저 있어야 한다. 조사가 여러 당직자에게 흩어져 있었고, 관찰 결과와 가설을 한곳에 모으지 않아 같은 가설이나 이미 버린 가설을 다시 붙잡기도 했다. 가설 하나를 버린 뒤에 다음 가설로 넘어가야 한다. 기존 지표에 없는 데이터는 DNStop 처럼 직접 모아야 한다. 멀티 테넌트 환경에서는 DNS 를 한 번 개선하면 모든 고객이 그 효과를 본다."},"related":[],"sources":[{"url":"https://adevinta.com/techblog/its-not-always-dns-unless-it-is/","kind":"blog","license":"unknown","archived":null}],"summary":{"en":"SCHIP clusters resolve names through CoreDNS for cluster.local and Amazon's resolver for external names, with a dnsmasq agent on every node as a local cache. In the most affected cluster, which had the highest DNS query volume in the fleet because of its pod density, its applications and CronJobs that ran every few hours, three problems added up and caused intermittent 5xx errors for about a month.\n\nFirst, dnsmasq allows 150 concurrent queries per node by default and the cluster exceeded it; the team raised the limit to 1500, as Google recommends. Second, dnsmasq cached only external answers: recent CoreDNS versions answer without the Recursion Available (RA) flag, and dnsmasq refuses to cache such answers, so every cluster.local query still went to CoreDNS. A CoreDNS header block that sets ra and aa and clears rd made dnsmasq cache local answers. Third, with the Kubernetes ndots setting, any name with fewer than five dots is first tried with every search domain, so short service names produced hundreds of unresolvable lookups per second.\n\nThe team made dnsmasq answer NXDOMAIN for those garbage names on the node instead of forwarding them, changed fluent-bit's log router address to a fully qualified name with five dots, and asked the affected tenants to use FQDNs. Requests reaching CoreDNS fell from more than 4000 per second to less than 1000 per second, and the DNS Latency SLI returned to above 99.9%. Two or three other large clusters had degraded SLIs from the same configuration.","ko":"Adevinta 는 쿠버네티스 위에 SCHIP 이라는 런타임을 만들어 20개가 넘는 테넌트의 마이크로서비스를 여러 클러스터에서 돌린다. 클러스터 DNS 는 CoreDNS 가 맡고, 노드마다 dnsmasq 가 로컬 DNS 캐시로 돌며 CoreDNS 로 가는 요청을 줄인다. DNS 품질은 내부 질의가 16ms 안에, 외부 질의가 64ms 안에 풀리는 비율로 잰다.\n\n한 클러스터에서 간헐적인 5xx 가 이어지는 동안 팀은 Ingress 컨트롤러와 노드 네트워크를 차례로 의심했지만 둘 다 원인이 아니었다. 영향받은 앱이 서비스 이름으로 내부 호출을 하는 프록시라는 점, fluent-bit 도 서비스 이름으로 로그 포워더를 부른다는 점에서 DNS 로 범위를 좁혔다. 이 클러스터의 DNS Latency SLI 는 꽤 오래 나빴지만, 다른 클러스터에 영향이 없어서 무시해 왔다.\n\n세 가지 원인이 겹쳐 있었다. 첫째, dnsmasq 는 기본으로 노드당 동시 DNS 질의를 150개까지만 받는데 이 클러스터는 그 한도를 넘었다. 한도를 1500으로 올리자 SLI 가 바로 좋아졌지만 한 주 만에 다시 나빠졌다. 둘째, dnsmasq 가 외부 질의만 캐시하고 cluster.local 질의는 전부 CoreDNS 로 넘기고 있었다. 최근 CoreDNS 버전의 변경으로 응답에 Recursion Available 플래그가 빠졌고, dnsmasq 는 이 플래그가 없는 응답을 캐시하지 않는다. CoreDNS 가 RA 비트를 항상 넣도록 바꾸자 캐시 적중률이 크게 좋아졌지만, 한 주 뒤 SLI 가 다시 떨어졌다. 셋째, 문제 노드에서 DNStop 을 돌려 보니 ndots 문제로 생긴 풀 수 없는 도메인 질의가 초당 수백 건씩 쏟아지고 있었다. 점이 5개보다 적은 이름은 밖으로 나가기 전에 로컬 검색 도메인을 하나씩 붙여 질의한다. schip.io.svc.cluster.local, cluster.local.cluster.local 같은 이름이 그 결과였다.\n\n이 질의를 dnsmasq 에서 NXDOMAIN 으로 끊고 fluent-bit 의 로그 라우터 호스트 이름을 FQDN 으로 바꾸자, CoreDNS 로 가는 요청이 초당 4000건이 넘던 데서 1000건 아래로 줄었다. DNS Latency SLI 는 99.9% 를 넘는 수준으로 돌아왔다. 설정은 모든 클러스터에 같았으므로 다른 큰 클러스터 두세 곳의 DNS 지연도 나빠져 있었다. 이 클러스터가 유독 심했던 것은 파드 밀도가 높고, 몇 시간마다 도는 CronJob 이 많아 DNS 질의가 가장 많았기 때문이다. 이 문제를 푸는 데 한 달이 걸렸다."},"trigger":null,"severity":"unknown","symptoms":["high-error-rate","dns-resolution-failures","high-latency"],"timeline":{"detected_after":null,"resolved_after":"1mo"},"date_kind":"published","detection":{"en":"A tenant reported a spike of HTTP 5xx errors in some of its services; the DNS Latency SLI had already been degraded for some time without being acted on.","ko":"고객이 SCHIP 에서 돌리는 일부 서비스의 HTTP 5xx 가 튄다고 알려 와서 알았다. DNS 와의 관계는 한참 뒤에야 드러났고, 그때 보니 그동안 무시해 온 이 클러스터의 DNS Latency SLI 가 다른 클러스터보다 낮아져 있었다."},"components":["coredns","dns-resolver","telemetry-agent"],"root_cause":"dns-network","remediation":[{"text":{"en":"raised the dnsmasq concurrent query limit from 150 to 1500","ko":"dnsmasq 의 노드당 동시 DNS 질의 한도를 150에서 Google 권장값인 1500으로 올렸다."}},{"text":{"en":"added a CoreDNS header block that sets the ra and aa flags and clears rd, so dnsmasq caches cluster.local answers","ko":"CoreDNS 가 응답에 RA 비트를 항상 넣도록 header 설정에 set ra aa, clear rd 를 넣어 dnsmasq 가 cluster.local 응답을 캐시하게 했다."}},{"text":{"en":"configured dnsmasq on each node to answer NXDOMAIN for unresolvable search-domain names instead of forwarding them to CoreDNS","ko":"노드 로컬 dnsmasq 에서 ndots 때문에 생긴 풀 수 없는 도메인 질의를 가로채 NXDOMAIN 으로 응답하도록 설정해 CoreDNS 로 넘어가지 않게 했다."}},{"text":{"en":"changed the fluent-bit log router hostname to a fully qualified name","ko":"fluent-bit 가 로그 라우터에 접속할 때 쓰는 호스트 이름을 서비스 이름에서 FQDN 으로 바꿨다."}},{"text":{"en":"asked the affected tenants to use fully qualified names for internal calls","ko":"영향받은 고객에게 앱의 내부 이름 해석을 FQDN 으로 바꾸도록 요청했다."}}],"action_items":[],"contributing":["default-config-unchanged","limit-unknown","early-signal-ignored","assumption-unverified"],"recurrence_of":null,"symptoms_text":{"en":"On a Friday afternoon a tenant of SCHIP, Adevinta's multi-tenant Kubernetes runtime, reported a spike of HTTP 5xx errors in some of its services. The drops in quality of service came back periodically through the following days, each one short, and were reported mostly around midnight.\n\nThe ingress controller was suspected first: its instance count had moved between two and five and showed a little CPU throttling. Raising its minimum instances and CPU removed the fluctuation and the throttling, but the errors continued. The errors then lined up with a recurring alert, \"A fluent-bit agent stopped processing logs\", from nodes where the affected service ran, and the team drained those nodes and restarted the Calico networking layer, as it had done for that alert before. That did not stop the reports either.\n\nA dedicated investigation found that most of the errors came from one application, a proxy that called many microservices by bare Kubernetes service names such as http://foo/api. Fluent-bit also reached its log forwarder by a short service name. The cluster's DNS Latency SLI, the share of internal lookups answered within 16 ms and external lookups within 64 ms, had been low compared with other clusters for some time, and DNS misses rose whenever quality of service dropped.\n\nThe dnsmasq logs on the nodes showed \"dnsmasq[25]: Maximum number of concurrent DNS queries reached (max: 150)\". After that limit was raised, the SLI improved and then slid back over a week; after the caching fix it degraded again a week later. Running DNStop on problem nodes showed hundreds of requests per second for names that cannot resolve, such as cluster.local.cluster.local, schip.io.svc.cluster.local and grafana.net.platform-services.svc.cluster.local.","ko":"어느 금요일 오후, 고객 한 곳이 SCHIP 에서 돌리는 일부 서비스에서 HTTP 5xx 오류가 튄다고 알려 왔다. 팀은 바로 장애를 선언했다.\n\n처음에는 클러스터 전체 트래픽을 받는 Ingress 컨트롤러를 의심했다. 그 시간대에 컨트롤러 인스턴스 수가 2개에서 5개 사이를 오갔고, CPU 스로틀링도 조금 있었다. 최소 인스턴스 수를 피크에 맞추고 CPU 를 늘렸지만, 월요일에 같은 문제가 계속된다는 보고가 다시 들어왔다. 인스턴스 수는 더 이상 흔들리지 않았고 스로틀링도 없었다. 문제는 하루에도 여러 번 짧게 되풀이됐다.\n\n다음에는 네트워크 문제를 의심했다. 성능이 떨어질 때 \"A fluent-bit agent stopped processing logs\" 알림이 함께 왔고, 5xx 를 낸 서비스가 그 fluent-bit 와 같은 노드에 있었다. 팀은 전부터 이 알림을 노드 문제로 보고 노드를 드레인한 뒤 네트워크 계층을 재시작해 왔다. 이번에도 그렇게 했지만 보고는 계속 들어왔고, 모든 보고가 kubenurse_errors_total 같은 네트워크 오류 지표와 맞아떨어지지도 않았다. 오류는 대체로 한 시간마다, 특히 자정 무렵에 많이 났다.\n\n영향받은 애플리케이션을 직접 들여다보니 품질 저하는 소수의 앱에서, 그중에서도 주로 프록시 앱 하나에서 나타났다. 이 앱은 http://foo/api 처럼 쿠버네티스 서비스 이름으로 내부 호출을 했다. fluent-bit 도 log-router-ingress-forward 라는 서비스 이름으로 로그 포워더를 불렀다. 이 클러스터의 DNS Latency SLI 는 다른 클러스터보다 한참 낮았고, 서비스가 나빠진 시각은 DNS 캐시 미스가 늘어난 시각과 겹쳤다. dnsmasq 로그에는 다음 줄이 찍혀 있었다.\n\nI0920 12:39:44.923951 6 nanny.go:146] dnsmasq[25]: Maximum number of concurrent DNS queries reached (max: 150)"},"updated_at":"2026-11-09T11:55:41.756475Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0083","org_slug":"adevinta"}