{"id":"IL-0080","org":"Mercari","date":"2025-06-04","docs":[],"title":{"en":"kube-dns on Mercari's GKE clusters could not keep up with peak-hour DNS query rates, and a Sev1 production outage followed when several services failed DNS resolution","ko":"트래픽이 몰린 GKE 클러스터에서 kube-dns 가 DNS 질의를 감당하지 못해 여러 서비스의 이름 해석이 실패하고 운영 장애로 번졌다."},"domain":["kubernetes","gcp","networking"],"impact":{"scope":"Multiple services on Mercari's GKE clusters failed DNS resolution and timed out, ending in a production outage","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"When every pod in a busy cluster resolves names through a few central kube-dns pods, DNS becomes a shared bottleneck, and a DNS failure quickly turns into higher latency, timeouts and cascading outages across microservices. A cache on each node takes most of that load off kube-dns and keeps resolution local to the node.\n\nRolling the cache out first to an internal test cluster with nodeAffinity, and then node pool by node pool through labels, kept the blast radius of the change small.","ko":"트래픽이 많은 쿠버네티스 클러스터에서는 DNS 를 최적화하는 일이 중요하다. 모든 파드가 몇 개의 kube-dns 파드에 기대는 구조는 피크 시간대에 장애 지점이 됐고, 노드 단위 캐시를 두자 DNS 트래픽과 오류가 크게 줄었다."},"related":[],"sources":[{"url":"https://about.in.mercari.com/news/mercari-india/from-dns-failures-to-resilience-how-nodelocal-dnscache-saved-the-day-sanu-satyadarshi/","kind":"blog","license":"unknown","archived":null}],"summary":{"en":"Mercari runs its services on managed GKE clusters, where kube-dns comes pre-installed in the kube-system namespace and is scaled by the default kube-dns autoscaling. Every pod on every node sent its DNS queries for names such as [service name].[namespace].svc.cluster.local to a small number of kube-dns pods. At peak traffic those pods were overwhelmed, which produced NXDOMAIN errors, truncated responses and \"failed to refresh DNS cache\" errors, and finally a Sev1 incident in which services failed DNS resolution and the failures cascaded into a production outage.\n\nThe Platform Engineering team responded by deploying NodeLocal DNSCache, which runs a DNS cache on each Kubernetes node so that pods on that node ask the local cache before kube-dns. The team first deployed it on the Laboratory GKE cluster, which only platform teams use for internal testing, with a specific nodeAffinity, and then rolled it out gradually to the Dev and Prod environments by adding labels to node pools so that the NodeLocal DNSCache pods could be scheduled there.\n\nAfter the rollout, DNS calls to kube-dns fell by 10x and the DNS query rate of services on the cluster fell by 93%. DNS-level errors fell by 10x to 100x depending on the error class (10x for NXDOMAIN, 100x for truncated responses), and the \"failed to refresh DNS cache\" errors disappeared completely.","ko":"Mercari 는 관리형 GKE 클러스터에 기본으로 설치되는 kube-dns 로 서비스 이름을 IP 로 바꿨다. kube-dns 는 kube-system 네임스페이스의 Deployment 로 돌았고, 클러스터의 모든 서비스가 [service name].[namespace].svc.cluster.local 같은 이름을 풀 때 몇 개 안 되는 kube-dns 파드에 의존했다. 쿠버네티스는 kube-dns 오토스케일링을 기본으로 제공하지만, 피크 시간대에는 질의가 kube-dns 가 감당할 수 없을 만큼 몰렸다. NXDOMAIN, 잘린 응답, \"failed to refresh DNS cache\" 오류가 반복됐다.\n\n결정타는 Sev1 장애였다. 여러 서비스가 DNS 이름 해석에 실패하면서 요청이 타임아웃으로 끝났고, 마이크로서비스가 연쇄로 묶여 있어서 결국 운영 장애로 이어졌다.\n\nPlatform Engineering 팀은 노드마다 DNS 캐시를 두는 NodeLocal DNSCache 를 해법으로 골랐다. 같은 노드의 파드가 kube-dns 로 가기 전에 그 노드의 캐시를 먼저 쓰게 해서, kube-dns 부하와 노드 사이 트래픽을 줄이는 방식이다. 팀은 내부 시험용 클러스터에서 효과를 먼저 재고 Dev 와 Prod 로 차례로 넓혔다. 배포 뒤 kube-dns 로 가는 DNS 호출은 10배 줄었고, 클러스터 서비스의 DNS 질의율은 93% 낮아졌다. DNS 오류는 종류에 따라 10배에서 100배 줄었는데, NXDOMAIN 은 10배, 잘린 응답은 100배였다. \"failed to refresh DNS cache\" 오류는 완전히 사라졌다."},"trigger":{"en":"Peak-hour traffic on the GKE clusters produced more DNS queries than the few kube-dns pods could answer.","ko":"피크 시간대에 클러스터가 처리하는 초당 요청 수가 크게 늘면서 DNS 질의가 소수의 kube-dns 파드로 몰렸다."},"severity":"sev1","symptoms":["dns-resolution-failures","intermittent-timeouts","service-unavailable"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"During peak hours the team saw frequent NXDOMAIN and truncated-response errors and recurring \"failed to refresh DNS cache\" errors on the clusters, which showed that kube-dns had reached its limits.","ko":"피크 시간대에 NXDOMAIN, 잘린 응답, \"failed to refresh DNS cache\" 오류가 반복되는 것을 보고 kube-dns 가 한계에 이르렀다는 것을 알았다."},"components":["kube-dns"],"root_cause":"capacity","remediation":[{"text":{"en":"deployed NodeLocal DNSCache on the Laboratory GKE cluster with a specific nodeAffinity to measure its effect","ko":"Platform 팀만 내부 시험용으로 쓰는 Laboratory GKE 클러스터에 nodeAffinity 를 걸어 NodeLocal DNSCache 를 배포하고, 전체 워크로드에 영향을 주지 않은 채 효과를 측정했다."}},{"text":{"en":"rolled NodeLocal DNSCache out gradually to the Dev and Prod environments by labelling node pools so its pods could be deployed there","ko":"노드 풀에 레이블을 붙여 NodeLocal DNSCache 파드가 뜰 수 있게 하는 방식으로 Dev 와 Prod 환경 전체에 점진적으로 배포했다."}}],"action_items":[],"contributing":["no-caching","single-point-of-failure"],"recurrence_of":null,"symptoms_text":{"en":"During peak hours, when Mercari's GKE clusters handle very high request rates, the platform team saw kube-dns reaching its limits. DNS query rates were high enough to overwhelm the kube-dns service.\n\nThe errors showed up at the DNS level: frequent NXDOMAIN answers, truncated responses, and a recurring \"failed to refresh DNS cache\" error that led to cache misses. The author says this last error was behind many production incidents.\n\nThe problem peaked in a Sev1 incident. Several services began to fail DNS resolution, their calls timed out, and because the microservices depend on each other the failures cascaded into a production outage.","ko":"Mercari 의 GKE 클러스터에서 여러 서비스가 한꺼번에 DNS 이름 해석에 실패하기 시작했다. 요청은 타임아웃으로 끝났고, 마이크로서비스가 서로 엮여 있어서 실패가 연쇄로 번지며 운영 장애가 됐다. 회사는 이 장애를 Sev1 로 분류했다.\n\n이 장애 전부터 피크 시간대마다 kube-dns 가 한계를 드러냈다. DNS 질의가 많아지면 kube-dns 가 이를 감당하지 못했고, NXDOMAIN 과 잘린 응답 같은 DNS 오류가 자주 났다.\n\n\"failed to refresh DNS cache\" 오류도 반복됐다. 이 오류는 캐시 미스를 일으켰고, 그동안 여러 운영 장애의 원인이 됐다."},"updated_at":"2026-11-09T11:55:41.318275Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0080","org_slug":"mercari"}