IL-0445 Chatwork · 2021-01-05 (게시일)kubernetesawsnetworking
EKS 로 옮기던 레거시 시스템에서 conntrack 테이블이 넘쳐 연결이 끊겼고, 이어 CoreDNS 파드가 축출될 때와 node-local-dns 를 넣은 뒤에 DNS 오류가 났다
Chatwork 는 2020년에 EC2 에서 돌던 레거시 시스템을 EKS 로 옮겼다. Route53 가중치로 두 쪽을 함께 돌리며 일정 비율이 넘는 요청을 EKS 로 보내자 서비스가 불안정해졌다. 일부 노드에서 conntrack 테이블이 넘쳐 애플리케이션으로 가는 연결이 끊겼고, 테이블을 채운 것은 CoreDNS 항목이었다. CoreDNS 는 EKS 기본값인 파드 2개뿐이어서 일부 CoreDNS 에 요청이 몰렸다. 다른 쿠버네티스 애플리케이션은 dns-autoscaler 가 처음부터 들어 있는 kube-aws 클러스터에서 돌았고, 팀은 EKS 에 dns-autoscaler 를 넣는 것을 잊고 있었다. 팀은 kube-proxy 설정에서 conntrack 의 maxPerCore 를 늘리고 dns-autoscaler 를 넣었다. CoreDNS 파드가 어느 정도 늘자 서비스가 크게 안정됐다.
그 뒤에도 노드가 모두 스폿 인스턴스여서, 노드가 바뀌며 CoreDNS 파드가 축출될 때 애플리케이션에 DNS 오류가 났다. 팀은 node-local-dns 를 넣었다. node-local-dns 는 각 노드에 DaemonSet 으로 실행되고, 노드가 사라질 때도 끝까지 남는다. 클러스터 전체의 DNS 요청과 CoreDNS 가 도는 노드의 conntrack 항목을 더 줄이려는 목적도 있었다.
node-local-dns 를 운영 환경에 apply 하자 DNS 가 다시 불안정해졌고, node-local-dns 로그에 timeout 이 잦았다. AWS 문서는 EC2 에서 CoreDNS 를 돌릴 때 force_tcp 를 쓰지 말라고 권한다. EC2 Nitro 인스턴스에서 DNS 요청을 전달하는 소프트웨어는 동시 TCP 연결을 2개까지만 받고, 연결마다 TCP 쿼리가 끝날 때까지 막힌다. 팀은 force_tcp 를 빼는 데서 그치지 않고 prefer_udp 로 바꿨고, DNS 가 안정됐다.
- 심각도
- –
- 영향 범위
- The legacy system being moved to EKS: connections to the application were dropped and applications got DNS errors
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
Route53 가중치로 EC2 와 EKS 를 함께 돌리며 레거시 시스템을 옮기던 중, 일정 비율이 넘는 요청을 EKS 쪽으로 보내자 서비스가 갑자기 불안정해졌다. 일부 노드에서 conntrack 테이블이 한계를 넘어 애플리케이션으로 가는 연결이 드롭되고 있었다.
conntrack 테이블을 조사하니 CoreDNS 항목이 많았다. CoreDNS 는 EKS 기본값인 파드 2개로 돌고 있어서 일부 CoreDNS 에 요청이 몰렸고, 그 노드의 conntrack 테이블이 넘쳤다. 두 CoreDNS 파드의 CPU 도 꽉 차 있었다.
conntrack 상한을 늘리고 dns-autoscaler 를 넣은 뒤 대체로 안정됐지만, CoreDNS 파드가 사라질 때마다 애플리케이션에서 DNS 오류가 났다. Chatwork 의 노드 그룹은 모두 스폿 인스턴스여서 노드가 종종 교체되었고, 그때 CoreDNS 파드도 축출되었다. 글쓴이는 CoreDNS 가 축출되면서 처리 중이던 DNS 요청이 오류가 된 것으로 봤다. 자세히 추적하지는 않았지만 시점이 맞았다고 적었다.
node-local-dns 를 넣자마자 요청이 훨씬 많은 운영 환경에서 DNS 가 다시 불안정해졌다. test 와 stg 에서는 동작을 확인한 뒤였다. node-local-dns 의 로그에는 timeout 이 잦았고, 설정 파일에는 문제가 없어 보였다.
글쓴이는 eksctl 로 DNS 대상을 바꾼 노드 그룹을 만들기 전에는 node-local-dns 가 쓰이지 않는다고 생각하고 있었다. 그래서 timeout 이 잦자 크게 당황했다. 실제로는 node-local-dns 가 시작할 때 dummy device 와 iptables 설정을 만들어 kube-dns 로 가는 요청을 자기에게 돌리므로, 넣자마자 요청이 node-local-dns 를 거쳤다.
DNS 가 불안정하던 동안에는 DNS 조회가 막혀 파드 수도 쓸데없이 늘었다.
원인
원인 용량 한계
- 촉발
- 첫 번째 불안정은 Route53 가중치로 EKS 쪽에 보내는 요청 비율을 일정 이상으로 올리면서 시작됐다. 두 번째 불안정은 문서에 나온 매니페스트로 force_tcp 를 쓰는 node-local-dns 를 운영 환경에 apply 하면서 시작됐다.
감지
–
조치
- conntrack 상한이 기본값과 다른 값으로 설정되어 있었고 그 값은 kube-proxy 가 정하고 있었다. 팀은 kube-proxy 설정에서 conntrack 의 maxPerCore 를 늘렸다.
- EKS 에 빠져 있던 dns-autoscaler 를 넣었다. CoreDNS 파드가 어느 정도 늘자 서비스가 크게 안정됐다.
- CoreDNS 파드가 축출될 때 나던 DNS 오류를 없애려고 각 노드에 DaemonSet 으로 실행되는 node-local-dns 를 넣었다.
- node-local-dns 설정에서 force_tcp 를 빼고 prefer_udp 로 바꾸자 DNS 가 안정됐다.
후속 조치
–
교훈
EKS 에서 DNS 를 안정시킨 것은 dns-autoscaler 를 넣은 것과, force_tcp 없이 node-local-dns 를 넣은 것 두 가지였다. node-local-dns 를 쓸 때는 eksctl 로 kubelet 의 DNS 대상을 바꿀 필요가 없고, kube-dns 를 그대로 두면 된다. node-local-dns 를 업데이트하는 동안처럼 잠시 쓸 수 없을 때는 dummy device 덕에 애플리케이션의 DNS 요청이 CoreDNS 로 바로 가므로 클러스터 전체의 가용성이 오른다. DNS 가 불안정하면 조회가 막혀 파드가 쓸데없이 늘어나므로, 파드 수를 알맞게 유지하는 데도 DNS 안정이 중요하다.
출처
참고 문서
관련 사례
IL-0048대형 EKS 클러스터에서 CoreDNS 가 VPC DNS 리졸버로 보내는 질의가 링크 로컬 트래픽의 초당 1024 패킷 한도에 걸려 DNS 조회가 간헐적으로 타임아웃됐다.unknown · 2025같은 원인 · 공통 CoreDNS, VPC DNS 리졸버, 클라이언트 쪽 DNS 리졸버와 캐시
같은 원인 · 공통 CoreDNS, 클라이언트 쪽 DNS 리졸버와 캐시
같은 원인 · 공통 CoreDNS, 클라이언트 쪽 DNS 리졸버와 캐시
같은 원인 · 공통 kube-proxy, conntrack 테이블
IL-0033kube-dns 파드 사이의 트래픽 불균형과 DNS 초당 패킷 한도 때문에 외부 DNS 조회가 많은 여러 서비스의 지연 시간이 20초까지 늘었다Airbnb · 2019같은 원인 · 공통 kube-proxy, 클라이언트 쪽 DNS 리졸버와 캐시
같은 원인 · 공통 CoreDNS, 클라이언트 쪽 DNS 리졸버와 캐시
IL-0102배포와 워커 오토스케일링 폭주가 겹치자 크기를 고정해 둔 CoreDNS 가 메모리 한도를 넘겨 재시작된 뒤 회복하지 못했고, Buildkite 사이트 전체가 약 30분 멈췄다.Buildkite · 2026같은 원인 · 공통 CoreDNS
IL-0155NYC1 의 일부 DOKS 클러스터에서 공유 CPU 노드 위의 CoreDNS 때문에 DNS 가 간헐적으로 실패하고 NodeNotReady 가 났다DigitalOcean · 2026같은 원인 · 공통 CoreDNS
IL-0082EKS 노드 교체 중 CoreDNS 파드 하나가 종료되자 남은 CoreDNS 파드가 늘어난 부하를 버티지 못해 DNS 조회가 느려지고 타임아웃이 났다.RebelMouse · 2025같은 원인 · 공통 CoreDNS
IL-0170설날 이벤트 트래픽이 평소의 3배를 넘자 Istio ingressGateway 가 있는 EKS 노드의 nf_conntrack 테이블이 가득 차 패킷이 버려졌고, 웹과 앱 서비스 전체가 멈췄다.Backpackr · 2025같은 원인 · 공통 conntrack 테이블
IL-0204Render 프랑크푸르트 클러스터에서 etcd 메모리 급증으로 컨트롤 플레인이 과부하에 걸렸고, 컨트롤 플레인 노드를 재부팅하자 그 위의 CoreDNS 가 다시 뜨지 못해 DNS 가 멈췄다.Render · 2024같은 원인 · 공통 CoreDNS
IL-0440파드가 보낸 DNS 쿼리 패킷이 노드에서 버려져 클러스터 내부 서비스의 이름 조회가 no such host 와 i/o timeout 으로 자주 실패했다Cybozu · 2024같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0182트래픽이 급변할 때 수가 모자란 CoreDNS 가 과부하로 지연과 간헐적 네트워크 끊김을 일으켰고, 나중에는 과하게 늘린 CoreDNS 파드가 Karpenter 의 노드 통합을 막았다이언철 · 2024같은 원인 · 공통 CoreDNS
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0445
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0445/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.