- Published on
EKS conntrack 테이블 포화로 연결 끊김 해결법
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서버가 멀쩡해 보이는데도 EKS에서 갑자기 연결이 끊기거나(특히 짧은 HTTP 요청이 폭증할 때), DNS/STS/외부 API 호출이 간헐적으로 타임아웃 나고, 노드 재부팅/스케일아웃을 하면 잠깐 괜찮아졌다가 다시 악화되는 패턴이라면 conntrack 테이블 포화를 의심해야 합니다.
Linux 커널의 conntrack(netfilter connection tracking)은 NAT, kube-proxy(iptables 모드), 일부 CNI 동작에서 핵심 역할을 합니다. 문제는 이 테이블이 노드 단 공유 자원이라서 특정 노드에 연결이 몰리거나, 짧은 연결이 폭증하거나, TIME_WAIT/UDP 트래킹이 길게 남으면 테이블이 꽉 차고 그 순간부터는 신규 연결이 드롭/지연되며 애플리케이션 레벨에서는 “간헐적 네트워크 장애”처럼 보인다는 점입니다.
이 글에서는 (1) 증상 식별 → (2) 노드에서 실제 포화 확인 → (3) 즉시 완화(응급처치) → (4) 근본 해결(튜닝/아키텍처) 순으로 정리합니다. 네트워크가 원인인지 빠르게 가르는 체크리스트는 EKS Pod는 뜨는데 트래픽 0 - NetPol·SG·CNI 10분 진단도 함께 참고하면 좋습니다.
1) 이런 증상이면 conntrack을 최우선으로 의심
다음이 여러 개 동시 발생하면 가능성이 큽니다.
- 특정 노드에 스케줄된 Pod들에서만 간헐적 타임아웃/연결 리셋
- HPA로 Pod 수를 늘려도 해결이 안 되거나, 오히려 노드 단에서 더 악화
- ALB/NLB 뒤에서는 5xx가 늘고, 애플리케이션 로그에는 “upstream timeout”, “connection reset by peer” 류가 증가
- CoreDNS는 Healthy인데도 DNS 질의가 간헐 실패(실제로는 UDP conntrack 포화로 드롭)
- 노드 dmesg/journal에 아래와 유사한 로그
nf_conntrack: table full, dropping packet
특히 짧은 HTTP 요청 폭증, SSE/WebSocket/장기 연결 + 재연결 폭주, NAT를 타는 아웃바운드 트래픽 폭증이 결합되면 conntrack은 생각보다 빨리 찹니다. 스트리밍/장기 연결이 프록시 설정 때문에 끊기며 재시도가 폭증하는 케이스도 함께 점검하세요: FastAPI Uvicorn에서 SSE 웹소켓 LLM 스트리밍이 프록시 뒤에서 끊길 때...
2) 노드에서 “진짜로” conntrack 포화인지 확인하기
2.1 커널 로그 확인
노드에 접속(SSM, SSH, 또는 Bottlerocket이면 admin container/로그 수집)해서 확인합니다.
# Amazon Linux 2 / Ubuntu 등
sudo dmesg -T | egrep -i 'conntrack|nf_conntrack' | tail -n 50
# systemd journal을 쓰는 경우
sudo journalctl -k | egrep -i 'conntrack|nf_conntrack' | tail -n 50
대표적으로 아래가 보이면 거의 확정입니다.
nf_conntrack: table full, dropping packet
2.2 현재 사용량/최대치 확인
# 현재 conntrack 엔트리 수
cat /proc/sys/net/netfilter/nf_conntrack_count
# 최대 엔트리 수
cat /proc/sys/net/netfilter/nf_conntrack_max
count가 max에 근접(예: 90% 이상)하고, 장애 시간대에 max를 때리면 원인으로 충분합니다.
2.3 어떤 트래픽이 엔트리를 먹는지(상위 포트/상태)
conntrack-tools가 있으면 가장 편합니다.
# 설치(배포판에 따라 다름)
# Amazon Linux 2
sudo yum install -y conntrack-tools
# Ubuntu
sudo apt-get update && sudo apt-get install -y conntrack
# 상위 엔트리 샘플
sudo conntrack -S
sudo conntrack -L | head
conntrack -S에서 insert_failed, drop이 증가하거나, 특정 프로토콜(TCP/UDP)에서 비정상적으로 엔트리가 쌓이는지 봅니다.
> 운영 환경에서 conntrack -L은 테이블이 큰 경우 비용이 큽니다. 가능하면 -S(통계) 위주로 보고, 필요한 경우에만 필터링해서 짧게 확인하세요.
2.4 kube-proxy 모드(iptables vs IPVS) 확인
iptables 모드는 conntrack 의존이 더 커지는 경우가 흔합니다.
kubectl -n kube-system get cm kube-proxy -o yaml | sed -n '1,200p'
# 또는 kube-proxy Pod args 확인
kubectl -n kube-system get ds kube-proxy -o yaml | egrep -n 'mode|ipvs|iptables' -n
3) 응급처치: 지금 당장 끊김을 줄이는 방법
3.1 nf_conntrack_max 상향(재부팅/재생성 후에도 유지되게)
노드에서 일시적으로 올리면 즉시 완화되는 경우가 많습니다.
# 예: 262144로 상향(노드 메모리 여유/트래픽 규모에 맞게 조정)
sudo sysctl -w net.netfilter.nf_conntrack_max=262144
# 현재 확인
sysctl net.netfilter.nf_conntrack_max
하지만 이건 임시 처치입니다. 노드 재부팅이나 자동 스케일링으로 새 노드가 뜨면 원복됩니다. EKS에서는 보통 아래 중 하나로 “영구 적용”을 합니다.
- Launch Template user-data로 sysctl 적용
- DaemonSet으로 privileged init 컨테이너에서 sysctl 적용(보안/정책 검토 필요)
- (Bottlerocket) settings로 sysctl 지원 여부 확인 후 적용
DaemonSet 방식 예시는 다음과 같습니다(환경에 맞게 최소 권한/정책 검토 필요).
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: sysctl-conntrack
namespace: kube-system
spec:
selector:
matchLabels:
app: sysctl-conntrack
template:
metadata:
labels:
app: sysctl-conntrack
spec:
hostPID: true
hostNetwork: true
containers:
- name: sysctl
image: public.ecr.aws/amazonlinux/amazonlinux:2
securityContext:
privileged: true
command:
- sh
- -c
- |
sysctl -w net.netfilter.nf_conntrack_max=262144
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30
sleep 3600
tolerations:
- operator: Exists
nf_conntrack_tcp_timeout_time_wait를 줄이는 것은 상황에 따라 도움이 되지만, 너무 공격적으로 줄이면 정상 연결에도 영향을 줄 수 있습니다. 먼저 max 상향 + 원인 트래픽 개선을 우선하세요.
3.2 문제 노드 격리(드레인)로 영향 범위 축소
특정 노드에서만 포화가 심하면 일단 해당 노드를 교체해 서비스 영향 범위를 줄일 수 있습니다.
kubectl cordon <node>
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data
다만 원인이 트래픽 패턴/설정이면 새 노드에서도 재발합니다.
4) 근본 해결: 왜 conntrack이 차는지 줄기부터 자르기
conntrack 포화는 “테이블을 키우면 끝”이 아니라, 엔트리를 과도하게 만드는 트래픽/구성을 함께 고쳐야 재발이 멈춥니다.
4.1 짧은 연결 폭증: Keep-Alive/커넥션 풀 재점검
- 서비스 간 HTTP 호출에서 Keep-Alive가 꺼져 있거나
- 클라이언트가 커넥션 풀을 못 쓰고 매 요청마다 새 TCP 연결을 만들거나
- 프록시/로드밸런서가 연결을 잘게 끊어 재연결이 폭증
이면 conntrack 엔트리가 빠르게 증가합니다.
예: Nginx 업스트림/클라이언트 Keep-Alive 기본을 점검합니다.
# 예시: 업스트림 keepalive로 백엔드 연결 재사용
upstream api_backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080;
keepalive 256;
}
server {
listen 80;
location / {
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://api_backend;
keepalive_timeout 65;
}
}
애플리케이션(예: Java/Go/Node/Python)도 커넥션 풀 크기/재사용을 확인하세요. “타임아웃이 나서 재시도 → 더 많은 새 연결 생성 → conntrack 더 악화”의 피드백 루프가 흔합니다.
4.2 UDP/DNS/STS 등 “간헐 타임아웃”을 만드는 숨은 주범
DNS가 간헐 실패해 애플리케이션이 재시도 폭탄을 만들면 conntrack이 더 빨리 찹니다. CoreDNS가 Healthy인데도 DNS가 튀는 케이스는 conntrack/노드 네트워크가 원인인 경우가 많습니다. 관련 진단 흐름은 EKS에서 CoreDNS 정상인데 DNS가 간헐 실패할 때도 같이 보세요.
또한 AWS API(STS, ECR, S3 등) 호출이 NAT를 통해 나가고, 재시도가 겹치면 노드/서브넷 단에서 연결이 폭증합니다. TLS handshake timeout이 함께 보이면 네트워크 경로(NAT, VPC, DNS)까지 같이 점검해야 합니다: EKS TLS handshake timeout 해결 - IRSA·VPC·CoreDNS
4.3 kube-proxy를 IPVS로 전환 검토(가능한 경우)
환경에 따라 iptables보다 IPVS가 스케일에 유리하고 conntrack 압박을 줄이는 데 도움이 될 수 있습니다(단, 모든 환경에서 만능은 아니며 운영 표준/관측/호환성 검토 필요).
- 현재 iptables 모드 + 대규모 서비스/엔드포인트라면 전환 가치가 있습니다.
- 이미 AWS VPC CNI + kube-proxy iptables에서 큰 문제 없이 운영 중이라면, 먼저 “트래픽 패턴 개선 + conntrack 튜닝”부터 하는 편이 안전합니다.
4.4 노드 사이즈/ENI/IP 할당과 함께 보기
conntrack은 메모리를 사용합니다. 무작정 max를 키우면 노드 메모리 압박이 생길 수 있고, 그 결과 다른 장애(OOM, kubelet 불안정)로 번질 수 있습니다. 노드 메모리 여유가 부족하거나 Pod가 OOMKilled를 반복한다면 리소스 튜닝도 병행해야 합니다: EKS Pod OOMKilled 반복 원인과 메모리·GC·Limit 튜닝
체크 포인트:
- 노드 타입(메모리) 상향이 가능한가
- 특정 노드에만 트래픽이 쏠리는 구조(세션 어피니티, 특정 AZ 편중, DaemonSet 엔드포인트 등)가 있는가
- AWS VPC CNI에서 Pod 밀도/ENI 설정이 과도해 노드에 네트워크 부하가 집중되는가
5) 권장 운영 패턴: “관측 + 가드레일”로 재발 방지
5.1 노드 단 메트릭 수집(최소한 count/max)
Prometheus node-exporter만으로는 conntrack을 기본으로 안 주는 경우가 많아, 텍스트파일 컬렉터나 전용 exporter를 붙입니다. 가장 단순한 방법은 텍스트파일 컬렉터를 쓰는 것입니다.
# 예: cron/daemonset로 주기 실행해 /var/lib/node_exporter/textfile_collector/conntrack.prom 생성
COUNT=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
cat <<EOF | sudo tee /var/lib/node_exporter/textfile_collector/conntrack.prom
node_nf_conntrack_count $COUNT
node_nf_conntrack_max $MAX
EOF
알람은 보통 아래처럼 잡습니다.
count / max > 0.8경고count / max > 0.9치명- 커널 로그에서
table full발생 횟수 증가 감지
5.2 배포 전 부하/재시도 정책 점검
- 클라이언트 재시도(backoff/jitter) 설정이 공격적이지 않은지
- 타임아웃이 너무 짧아 재시도를 유발하지 않는지
- 장기 연결(SSE/WebSocket)에서 프록시 타임아웃/버퍼링 때문에 불필요한 재연결이 발생하지 않는지
이런 “애플리케이션 레벨의 연결 생성량”이 conntrack의 가장 큰 입력값입니다.
6) 빠른 결론: 가장 효과가 큰 순서
- 노드에서 dmesg로
nf_conntrack: table full확인 +count/max수치화 - 즉시 완화: nf_conntrack_max 상향(영구 적용 경로 마련)
- 원인 제거: Keep-Alive/커넥션 풀/재시도 폭탄 줄이기
- 구조 개선: kube-proxy 모드, NAT 경로, 트래픽 쏠림(특정 노드 편중) 해결
- 재발 방지: conntrack 사용률 알람 + 장애 시간대 상관관계(배포/트래픽/외부 장애) 기록
conntrack 포화는 “네트워크가 가끔 이상하다”로 뭉개고 넘어가면 계속 재발합니다. 반대로 한 번만 제대로 계측해서 count/max와 커널 로그를 붙이면, 원인이 명확해지고 해결도 빠릅니다.