{"id":"IL-0445","org":"Chatwork","date":"2021-01-05","docs":["https://github.com/awsdocs/amazon-eks-user-guide/blob/master/doc_source/kubernetes-versions.md#kubernetes-115","https://github.com/aws/amazon-vpc-cni-k8s/issues/595#issuecomment-658635050","https://github.com/kubernetes/enhancements/blob/master/keps/sig-network/0030-nodelocal-dns-cache.md"],"title":{"en":"Chatwork's service on EKS became unstable as conntrack tables on some nodes overflowed and connections were dropped","ko":"EKS 로 옮기던 레거시 시스템에서 conntrack 테이블이 넘쳐 연결이 끊겼고, 이어 CoreDNS 파드가 축출될 때와 node-local-dns 를 넣은 뒤에 DNS 오류가 났다"},"domain":["kubernetes","aws","networking"],"impact":{"scope":"The legacy system being moved to EKS: connections to the application were dropped and applications got DNS errors","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"On EKS, dns-autoscaler and node-local-dns made DNS stable, but node-local-dns must not use force_tcp there. Stable DNS also matters for sizing the number of pods correctly, since blocked DNS queries had made the pod count grow.","ko":"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 안정이 중요하다."},"related":[],"sources":[{"url":"https://creators-note.chatwork.com/entry/2021/01/05/104206","kind":"blog","archived":"https://web.archive.org/web/20260509171217/https://creators-note.chatwork.com/entry/2021/01/05/104206"}],"summary":{"en":"Chatwork runs EKS as a single multi-tenant cluster. When traffic to the legacy system on EKS rose during the migration from EC2, conntrack tables on some nodes overflowed and dropped connections. Most entries came from CoreDNS, which was still at the EKS default of two pods. The conntrack limit turned out to be set by kube-proxy to a value other than the default, so Chatwork raised maxPerCore in the conntrack section of the kube-proxy configuration, which the post shows as max: 0, maxPerCore: 32768, min: 131072, tcpCloseWaitTimeout: 1h0m0s, tcpEstablishedTimeout: 24h0m0s.\n\nAt the same time Chatwork installed dns-autoscaler. The clusters it had built earlier with kube-aws included dns-autoscaler from the start, and the team had forgotten to add it to EKS. Once CoreDNS ran with enough pods, the cluster became much more stable. To stop DNS errors when CoreDNS pods were evicted from spot nodes, and to cut cluster-wide DNS requests and conntrack entries on the CoreDNS nodes, Chatwork added node-local-dns, which runs on every node as a DaemonSet.\n\nWith node-local-dns, production DNS became unstable again and node-local-dns logged frequent timeouts. The cause was force_tcp: AWS recommends not using force_tcp with CoreDNS on EC2, and a comment quoted from an amazon-vpc-cni-k8s issue says the software forwarding DNS requests on EC2 Nitro instances is limited to 2 simultaneous TCP connections and blocks on TCP queries. Chatwork replaced force_tcp with prefer_udp, and DNS became stable. The final setup was dns-autoscaler plus node-local-dns without force_tcp. Because node-local-dns redirects requests for kube-dns to itself with a dummy device, application DNS requests go straight to CoreDNS when node-local-dns is temporarily unavailable, for example during its update.","ko":"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 파드가 어느 정도 늘자 서비스가 크게 안정됐다.\n\n그 뒤에도 노드가 모두 스폿 인스턴스여서, 노드가 바뀌며 CoreDNS 파드가 축출될 때 애플리케이션에 DNS 오류가 났다. 팀은 node-local-dns 를 넣었다. node-local-dns 는 각 노드에 DaemonSet 으로 실행되고, 노드가 사라질 때도 끝까지 남는다. 클러스터 전체의 DNS 요청과 CoreDNS 가 도는 노드의 conntrack 항목을 더 줄이려는 목적도 있었다.\n\nnode-local-dns 를 운영 환경에 apply 하자 DNS 가 다시 불안정해졌고, node-local-dns 로그에 timeout 이 잦았다. AWS 문서는 EC2 에서 CoreDNS 를 돌릴 때 force_tcp 를 쓰지 말라고 권한다. EC2 Nitro 인스턴스에서 DNS 요청을 전달하는 소프트웨어는 동시 TCP 연결을 2개까지만 받고, 연결마다 TCP 쿼리가 끝날 때까지 막힌다. 팀은 force_tcp 를 빼는 데서 그치지 않고 prefer_udp 로 바꿨고, DNS 가 안정됐다."},"trigger":{"en":"During the migration from EC2 to EKS, Chatwork sent more than a certain share of requests to the EKS side. Later, applying node-local-dns with force_tcp in its configuration made DNS unstable again.","ko":"첫 번째 불안정은 Route53 가중치로 EKS 쪽에 보내는 요청 비율을 일정 이상으로 올리면서 시작됐다. 두 번째 불안정은 문서에 나온 매니페스트로 force_tcp 를 쓰는 node-local-dns 를 운영 환경에 apply 하면서 시작됐다."},"severity":"unknown","symptoms":["intermittent-connection-failures","dns-resolution-failures","intermittent-timeouts","uneven-load"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":null,"components":["conntrack","coredns","kube-proxy","dns-resolver","vpc-dns-resolver"],"root_cause":"capacity","remediation":[{"text":{"en":"Raised the conntrack maxPerCore value in the kube-proxy configuration","ko":"conntrack 상한이 기본값과 다른 값으로 설정되어 있었고 그 값은 kube-proxy 가 정하고 있었다. 팀은 kube-proxy 설정에서 conntrack 의 maxPerCore 를 늘렸다."}},{"text":{"en":"Installed dns-autoscaler so CoreDNS ran with more pods","ko":"EKS 에 빠져 있던 dns-autoscaler 를 넣었다. CoreDNS 파드가 어느 정도 늘자 서비스가 크게 안정됐다."}},{"text":{"en":"Installed node-local-dns as a DaemonSet on every node","ko":"CoreDNS 파드가 축출될 때 나던 DNS 오류를 없애려고 각 노드에 DaemonSet 으로 실행되는 node-local-dns 를 넣었다."}},{"text":{"en":"Replaced force_tcp with prefer_udp in the node-local-dns configuration","ko":"node-local-dns 설정에서 force_tcp 를 빼고 prefer_udp 로 바꾸자 DNS 가 안정됐다."}}],"action_items":[],"contributing":["default-config-unchanged","staging-not-representative","limit-unknown"],"recurrence_of":null,"symptoms_text":{"en":"In 2020 Chatwork moved its legacy system from EC2 to EKS, running both sides in parallel with Route53 weighted records. Once more than a certain share of requests was sent to the EKS side, the service suddenly became unstable. On some nodes the conntrack table had gone past its limit and connections to the application were being dropped.\n\nMost entries in the conntrack tables were CoreDNS traffic. The cluster still ran the EKS default of two CoreDNS pods, so DNS requests piled onto them and filled the conntrack tables of their nodes, and the CPU of both CoreDNS pods was also close to full. While DNS was unstable, DNS queries blocked, and the number of pods grew more than needed.\n\nAfter the CoreDNS pods were scaled out, the application still got DNS errors whenever a CoreDNS pod went away, which happened regularly because Chatwork's node groups run entirely on spot instances. Judging from the timing, in-flight DNS requests seemed to fail when a CoreDNS pod was evicted.\n\nWhen node-local-dns was then applied from the documented manifest, after checking it in test and staging, DNS became unstable again in production, which has far more requests, and the node-local-dns logs showed frequent timeouts. The team had believed node-local-dns would not be used until node groups were created with eksctl settings pointing pods' DNS at it, so the timeouts were unexpected; in fact node-local-dns creates a dummy device and iptables rules at startup and takes over requests sent to kube-dns.","ko":"Route53 가중치로 EC2 와 EKS 를 함께 돌리며 레거시 시스템을 옮기던 중, 일정 비율이 넘는 요청을 EKS 쪽으로 보내자 서비스가 갑자기 불안정해졌다. 일부 노드에서 conntrack 테이블이 한계를 넘어 애플리케이션으로 가는 연결이 드롭되고 있었다.\n\nconntrack 테이블을 조사하니 CoreDNS 항목이 많았다. CoreDNS 는 EKS 기본값인 파드 2개로 돌고 있어서 일부 CoreDNS 에 요청이 몰렸고, 그 노드의 conntrack 테이블이 넘쳤다. 두 CoreDNS 파드의 CPU 도 꽉 차 있었다.\n\nconntrack 상한을 늘리고 dns-autoscaler 를 넣은 뒤 대체로 안정됐지만, CoreDNS 파드가 사라질 때마다 애플리케이션에서 DNS 오류가 났다. Chatwork 의 노드 그룹은 모두 스폿 인스턴스여서 노드가 종종 교체되었고, 그때 CoreDNS 파드도 축출되었다. 글쓴이는 CoreDNS 가 축출되면서 처리 중이던 DNS 요청이 오류가 된 것으로 봤다. 자세히 추적하지는 않았지만 시점이 맞았다고 적었다.\n\nnode-local-dns 를 넣자마자 요청이 훨씬 많은 운영 환경에서 DNS 가 다시 불안정해졌다. test 와 stg 에서는 동작을 확인한 뒤였다. node-local-dns 의 로그에는 timeout 이 잦았고, 설정 파일에는 문제가 없어 보였다.\n\n글쓴이는 eksctl 로 DNS 대상을 바꾼 노드 그룹을 만들기 전에는 node-local-dns 가 쓰이지 않는다고 생각하고 있었다. 그래서 timeout 이 잦자 크게 당황했다. 실제로는 node-local-dns 가 시작할 때 dummy device 와 iptables 설정을 만들어 kube-dns 로 가는 요청을 자기에게 돌리므로, 넣자마자 요청이 node-local-dns 를 거쳤다.\n\nDNS 가 불안정하던 동안에는 DNS 조회가 막혀 파드 수도 쓸데없이 늘었다."},"updated_at":"2026-11-14T12:34:09.438100Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0445","org_slug":"chatwork"}