{"id":"IL-0013","org":"loveholidays","date":"2020-02-15","docs":["https://en.wikipedia.org/wiki/Netfilter#Connection_tracking","https://github.com/prometheus/node_exporter","https://github.com/kubernetes/kubernetes/pull/74840","https://kubernetes.io/blog/2019/03/29/kube-proxy-subtleties-debugging-an-intermittent-connection-reset/","https://www.projectcalico.org/when-linux-conntrack-is-no-longer-your-friend/","https://www.zenko.io/blog/solving-connection-reset-issue-in-kubernetes/","https://technology.lastminute.com/chasing-k8s-connection-reset-issue/","https://tech.xing.com/a-reason-for-unexplained-connection-timeouts-on-kubernetes-docker-abd041cf7e02"],"title":{"en":"The conntrack table filled up on downsized GKE nodes and a high-traffic aggregation proxy saw climbing connection resets","ko":"노드 RAM 을 절반으로 줄이자 conntrack 테이블이 가득 차 집계 서비스에 연결 리셋과 오류가 늘었다"},"domain":["kubernetes","gcp","networking"],"impact":{"scope":"one aggregation service","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"The conntrack limit is tied to node memory, so resizing a node pool silently resizes the connection table, and on GKE the ratio did not match the commonly cited formula. A high-traffic proxy on small nodes can exhaust it, and the symptoms are connection resets and timeouts, so conntrack use needs its own metric and alert.","ko":"쿠버네티스 노드의 conntrack_max 는 노드 RAM 에 비례해 정해진다. 부하가 큰 애플리케이션은 특히 작은 노드에서 conntrack_max 를 쉽게 넘겨 연결 리셋과 타임아웃을 일으킨다. 노드를 작게 바꾸면 추적할 수 있는 연결 수도 함께 줄어든다. conntrack 사용률은 지표로 보고 경보를 걸어 둬야 한다."},"related":[],"sources":[{"url":"https://deploy.live/blog/kubernetes-networking-problems-due-to-the-conntrack/","kind":"blog","license":"unknown","archived":"http://web.archive.org/web/20260427131442/https://deploy.live/blog/kubernetes-networking-problems-due-to-the-conntrack/"}],"summary":{"en":"Connection tracking (conntrack) is the Linux netfilter feature that records every network connection so that NAT and stateful iptables rules can treat all packets of a connection the same way, and Kubernetes nodes depend on it heavily to route traffic between pods and services. The table has a maximum size, visible in the node_nf_conntrack_entries_limit metric or through sysctl net.ipv4.netfilter.ip_conntrack_max. The commonly cited default is CONNTRACK_MAX = RAMSIZE (in bytes) / 16384 / (x / 32), where x is the pointer size in bits, which makes the limit proportional to node memory. On GKE the team observed something different: roughly 5 conntrack entries per MB of memory.\n\nEither way the limit follows node memory, so halving the RAM of the aggregation nodes shrank the table at the same time as sharding doubled the connections the proxy had to track, and the table filled. The immediate fix was to schedule the aggregation service on nodes with more RAM and to limit how many of its pods run on one node. The team then added an alert on conntrack use above 75%. The write-up also points to a Kubernetes fix expected in version 1.15 or newer (pull request 74840), and to two ways of raising nf_conntrack_max with a privileged sysctl -w net.netfilter.nf_conntrack_max=262144, from an init container or from a DaemonSet on dedicated nodes. It warns that this lets an application manage infrastructure without knowing the node's default, that several applications can keep overwriting each other's value as pods come and go, and that a larger table can use more RAM and add latency.","ko":"conntrack 은 리눅스 커널이 네트워크 연결을 추적하는 기능이다. NAT 와 iptables 가 이 정보를 쓰고, 쿠버네티스 노드는 수많은 파드와 서비스 사이의 연결을 여기에 기록한다. 테이블 크기인 conntrack_max 는 노드 RAM 에 비례한다. loveholidays 가 GKE 노드에서 관찰해 보니 conntrack_max 는 메모리 1MB 당 대략 5였다.\n\nloveholidays 의 집계 서비스는 각각 인스턴스가 100개 넘는 두 서비스 사이에서 프록시 역할을 한다. 평소 초당 10,000건 넘는 요청을 처리하고, 기본 부하의 네 배까지 치솟기도 한다. 노드 RAM 을 절반으로 줄이고 추적할 연결을 두 배로 늘리자 일부 노드의 conntrack 테이블이 바닥났고, 연결 문제와 연결 리셋 오류가 생겼다.\n\n팀은 RAM 이 더 큰 노드에 애플리케이션을 배치하고 노드당 집계 서비스 파드 수를 제한해 당장의 문제를 풀었다. 쿠버네티스 1.15 이상에는 관련 수정이 들어 있을 것으로 보인다. init 컨테이너나 데몬셋에서 sysctl 로 conntrack_max 를 올리는 방법도 있다. 다만 이렇게 하면 애플리케이션이 인프라를 건드리게 되고, 여러 애플리케이션이 같은 값을 서로 덮어쓸 수 있으며, 노드 메모리 사용량과 지연도 늘 수 있다."},"trigger":{"en":"Three changes together: a change in service architecture, halving the RAM of the nodes that run the aggregation service, and sharding a downstream service, which doubled the number of connections to track.","ko":"집계 서비스가 도는 노드의 RAM 을 절반으로 줄였고, 하위 서비스를 샤딩하면서 추적해야 할 연결 수는 두 배가 됐다. conntrack_max 는 노드 RAM 에 비례하므로 노드가 추적할 수 있는 연결 수는 줄고 추적할 연결은 늘었다."},"severity":"unknown","symptoms":["connection-resets","high-error-rate","intermittent-connection-failures"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"Rising error rates and climbing connection reset errors in HAProxy, then node_exporter conntrack metrics compared with their limit.","ko":"팀은 먼저 서비스의 연결 문제와 오류율 상승을 알아챘다. HAProxy 가 보고하는 연결 리셋 오류가 계속 늘었고, 팀은 node_nf_conntrack_entries 를 node_nf_conntrack_entries_limit 과 겹쳐 보고 일부 노드의 conntrack 테이블이 바닥난 것을 확인했다."},"components":["conntrack","kube-proxy","node-pool","haproxy"],"root_cause":"capacity","remediation":[{"text":{"en":"moved the aggregation service to nodes with more RAM","ko":"집계 서비스를 RAM 이 더 큰 노드에 배치했다."}},{"text":{"en":"limited the number of aggregation service pods per node","ko":"노드 하나에 뜨는 집계 서비스 파드 수를 제한했다."}}],"action_items":[{"text":{"en":"Alert when conntrack table use goes above 75%, with (node_nf_conntrack_entries / on (pod) node_nf_conntrack_entries_limit / on (pod) group_right kube_pod_info) > 0.75","ko":"conntrack 사용률이 75% 를 넘으면 경보가 가도록 Prometheus 쿼리 (node_nf_conntrack_entries / on (pod) node_nf_conntrack_entries_limit / on (pod) group_right kube_pod_info) > 0.75 로 경보 규칙을 만들었다."}}],"contributing":["limit-unknown","no-capacity-planning","no-alert-on-limit"],"recurrence_of":null,"symptoms_text":{"en":"Shortly after a round of changes, loveholidays saw connectivity problems and raised error rates on its aggregation service. The service is a proxy between two other services of more than 100 instances each, handles over 10,000 requests per second continuously and can spike to four times that.\n\nThe application logged errors such as \"Caused by: org.apache.http.NoHttpResponseException: xxxxx failed to respond\", and HAProxy reported connection reset errors whose count kept climbing.\n\nThe team worked through the available networking metrics. Overlaying the node_exporter metric node_nf_conntrack_entries on node_nf_conntrack_entries_limit made it clear that some nodes were running out of conntrack table space. The query used was (node_nf_conntrack_entries / on (pod) node_nf_conntrack_entries_limit / on (pod) group_right kube_pod_info) * 100, which gives the percentage of the conntrack table in use on each pod's node.","ko":"서비스 구조를 바꾸고 노드 풀 크기를 조정하고 하위 서비스를 샤딩한 직후, 집계 서비스에 여러 연결 문제가 생기고 오류율이 올라갔다.\n\n애플리케이션에는 Caused by: org.apache.http.NoHttpResponseException: xxxxx failed to respond 오류가 찍혔다. HAProxy 가 보고하는 연결 리셋 오류는 계속 늘었다.\n\n팀은 네트워크 지표를 살피다가 Prometheus 지표 node_nf_conntrack_entries 와 node_nf_conntrack_entries_limit 을 겹쳐 보았고, 일부 노드의 conntrack 테이블 공간이 바닥나고 있다는 것을 알았다. 사용률은 다음 쿼리로 봤다. (node_nf_conntrack_entries / on (pod) node_nf_conntrack_entries_limit / on (pod) group_right kube_pod_info) * 100"},"updated_at":"2026-11-10T00:00:33.576433Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0013","org_slug":"loveholidays"}