- Published on
EKS kube-proxy를 IPVS로 바꾼 뒤 통신 장애 복구
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
서론
EKS에서 kube-proxy를 기본(iptables)에서 IPVS 모드로 전환하면, 대규모 서비스/엔드포인트 환경에서 룰 처리 성능과 안정성이 좋아지는 경우가 많습니다. 하지만 전환 직후 또는 특정 노드에서만 ClusterIP/NodePort/LoadBalancer 통신 장애가 발생하는 사례도 흔합니다. 이유는 단순히 mode: ipvs 한 줄로 끝나지 않기 때문입니다. IPVS는 커널 모듈/conntrack/라우팅/리버스 패스 필터(rp_filter)/보안그룹/헬스체크 경로 등 여러 요소가 맞물려 동작합니다.
이 글은 “IPVS로 바꿨더니 갑자기 서비스가 안 붙는다/간헐적으로 끊긴다/특정 노드에서만 장애가 난다” 상황에서, 원인별로 재현 가능한 체크리스트와 복구 방법을 제공합니다.
관련해서 네트워크 계층 진단이 필요할 때는 다음 글도 함께 보면 문제 범위를 빠르게 좁힐 수 있습니다.
IPVS 모드 전환 시 흔한 장애 증상 패턴
전환 이후 장애는 보통 아래 형태로 나타납니다.
1) ClusterIP로 접속 시 타임아웃
- Pod → Service(ClusterIP) 호출이 타임아웃
- 같은 Pod에서 Pod IP 직접 호출은 정상
2) 특정 노드에서만 장애
- 어떤 노드에 스케줄된 Pod만 서비스 호출 실패
- 노드 교체/재부팅 후 갑자기 정상화되거나 반대로 악화
3) NodePort/LoadBalancer 헬스체크 실패
- NLB/ALB 타겟 헬스체크가 Unhealthy
- 노드로 직접 NodePort 접속도 일부 노드에서 실패
이 패턴은 대부분 “IPVS 룰이 안 만들어짐”, “패킷이 들어오지만 rp_filter/라우팅/보안그룹에서 드랍”, “conntrack/IPVS 동기화 문제”로 귀결됩니다.
0단계: 지금 정말 IPVS로 동작 중인지 확인
먼저 kube-proxy가 IPVS 모드로 떠 있는지, 그리고 IPVS 테이블이 생성되는지 확인합니다.
# kube-proxy 모드 확인
kubectl -n kube-system get cm kube-proxy -o yaml | sed -n '/config.conf:/,/kind:/p'
# kube-proxy 로그에서 mode 확인
kubectl -n kube-system logs -l k8s-app=kube-proxy --tail=200 | egrep -i 'Using ipvs|ipvs|mode'
노드에서 직접 확인할 수 있으면 더 확실합니다.
# 노드에서 IPVS 상태 확인(호스트)
sudo ipvsadm -Ln
# kube-proxy가 만든 가상 서버(ClusterIP:Port)가 보여야 함
# 예: TCP 10.100.0.1:443 rr ...
ipvsadm: command not found면 패키지가 없을 수 있지만, 커널 IPVS는 있어도 유저툴이 없을 수 있습니다.ipvsadm -Ln이 비어 있으면 “모드만 IPVS인데 룰이 못 만들어지는 상태”일 가능성이 큽니다.
1단계: 커널 모듈 누락(가장 흔한 원인)
IPVS는 커널 모듈이 필요합니다. EKS AMI/커스텀 AMI/컨테이너 최적화 이미지 구성에 따라 모듈이 빠져 있거나, 부팅 시 자동 로드가 안 될 수 있습니다.
필수 모듈 체크
노드에서 아래를 확인합니다.
# 로드된 모듈 확인
lsmod | egrep 'ip_vs|nf_conntrack|br_netfilter'
# 필요한 모듈 로드 시도
sudo modprobe ip_vs
sudo modprobe ip_vs_rr
sudo modprobe ip_vs_wrr
sudo modprobe ip_vs_sh
sudo modprobe nf_conntrack
sudo modprobe br_netfilter
체크 포인트
nf_conntrack가 없으면 세션 추적이 불안정해지고, 서비스 NAT 경로가 꼬일 수 있습니다.br_netfilter가 없으면 브리지 네트워킹 환경에서 iptables/필터가 기대대로 동작하지 않을 수 있습니다.
부팅 시 자동 로드(권장)
노드 재부팅 후 재발을 막으려면 모듈을 영구 설정합니다(AMI/부트스트랩 스크립트에 포함).
# /etc/modules-load.d/ipvs.conf
cat <<'EOF' | sudo tee /etc/modules-load.d/ipvs.conf
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
nf_conntrack
br_netfilter
EOF
이 단계에서 많은 장애가 바로 해결됩니다. 그래도 계속되면 다음 단계로 넘어갑니다.
2단계: rp_filter(Reverse Path Filtering)로 인한 드랍
IPVS/DSR/노드 간 라우팅/다중 ENI 환경에서 rp_filter가 엄격 모드(1)로 되어 있으면, 리턴 패스가 “커널이 기대한 인터페이스”와 다를 때 패킷을 드랍합니다. EKS에서는 CNI 구성(특히 VPC CNI, 멀티 ENI, 소스 기반 라우팅)에 따라 이 문제가 더 잘 드러납니다.
증상
- 특정 노드/특정 경로에서만 타임아웃
- tcpdump로 보면 요청은 들어오는데 응답이 안 나가거나, 응답이 나가도 다시 드랍
확인
# 노드에서 rp_filter 확인
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter
sysctl net.ipv4.conf.eth0.rp_filter
해결(권장 값: 0 또는 2)
0: 비활성화2: loose mode(대부분의 클라우드 환경에서 안전한 절충)
# 즉시 반영
sudo sysctl -w net.ipv4.conf.all.rp_filter=0
sudo sysctl -w net.ipv4.conf.default.rp_filter=0
# 영구 반영
cat <<'EOF' | sudo tee /etc/sysctl.d/99-eks-ipvs.conf
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
EOF
sudo sysctl --system
운영 환경에서는 보안/정책 요구에 따라 2(loose)를 선택하는 경우도 많습니다.
3단계: IPVS는 되는데 트래픽이 특정 엔드포인트로만 안 붙는 경우
이 경우는 대개 아래 중 하나입니다.
3-1) kube-proxy의 strictARP 설정 문제(특히 MetalLB/ARP 경로)
온프레미스나 L2 기반 로드밸런서(MetalLB)와 결합하는 경우 strictARP가 중요합니다. EKS + AWS NLB 환경에서는 일반적으로 필수는 아니지만, 혼합 환경/특수 구성에서는 영향이 있을 수 있습니다.
kube-proxy ConfigMap에서 확인합니다.
kubectl -n kube-system get cm kube-proxy -o jsonpath='{.data.config\.conf}' | yq
필드 예:
mode: "ipvs"
ipvs:
strictARP: true
- L2/ARP 기반 환경이면
strictARP: true가 권장입니다.
3-2) conntrack 테이블 부족
IPVS는 conntrack 의존도가 큽니다. 트래픽이 많거나 엔드포인트가 많으면 conntrack이 부족해 드랍/리셋이 발생할 수 있습니다.
# 현재 사용량/최대치
cat /proc/sys/net/netfilter/nf_conntrack_count
cat /proc/sys/net/netfilter/nf_conntrack_max
# dmesg에서 conntrack drop 확인
dmesg | egrep -i 'conntrack|nf_conntrack|table full'
임시 상향:
sudo sysctl -w net.netfilter.nf_conntrack_max=524288
영구 반영:
cat <<'EOF' | sudo tee /etc/sysctl.d/99-conntrack.conf
net.netfilter.nf_conntrack_max = 524288
EOF
sudo sysctl --system
값은 노드 메모리/트래픽에 맞춰 산정해야 합니다(무작정 키우면 메모리 사용량이 증가).
4단계: NodePort/LoadBalancer 장애면 보안그룹과 헬스체크 경로부터
IPVS 전환 자체가 SG를 바꾸진 않지만, 전환 후 장애가 드러나면서 “원래도 불완전했던 SG/헬스체크”가 표면화되는 케이스가 많습니다.
점검 포인트
- 노드 SG 인바운드에 **NodePort 범위(기본 30000-32767)**가 열려 있는가?
- NLB 타겟 그룹 헬스체크 포트가 NodePort로 맞는가?
externalTrafficPolicy: Local을 쓰는 Service에서, 헬스체크가 “엔드포인트 없는 노드”로도 가고 있진 않은가?
예: Service 설정 확인
kubectl get svc -A -o wide
kubectl -n <ns> get svc <svc> -o yaml | egrep -n 'type:|externalTrafficPolicy|healthCheckNodePort|ports:' -n
externalTrafficPolicy: Local이면 엔드포인트가 없는 노드는 헬스체크에 실패할 수 있습니다. 이건 IPVS 문제가 아니라 트래픽 정책의 특성입니다.
5단계: kube-proxy 룰/엔드포인트 동기화가 꼬였을 때(롤링 재기동)
구성이 올바른데도 특정 시점부터 룰이 업데이트되지 않거나, ipvsadm -Ln이 기대와 다르면 kube-proxy를 안전하게 재기동해 복구하는 것이 빠릅니다.
# kube-proxy 롤링 재시작
kubectl -n kube-system rollout restart ds/kube-proxy
# 진행 확인
kubectl -n kube-system rollout status ds/kube-proxy
노드 단위로만 문제가 있으면 해당 노드의 kube-proxy Pod만 재시작해도 됩니다.
# 특정 노드의 kube-proxy Pod 식별
kubectl -n kube-system get pod -o wide -l k8s-app=kube-proxy | grep <node-name>
# Pod 삭제(자동 재생성)
kubectl -n kube-system delete pod <kube-proxy-pod>
6단계: 장애 재현/원인 분리용 패킷/라우팅 체크
원인을 “서비스 레벨”이 아니라 “패킷 레벨”에서 분리하면 훨씬 빨리 결론이 납니다.
6-1) Pod에서 서비스/엔드포인트 직접 비교
# 임시 디버그 Pod
kubectl run -it --rm netdebug --image=nicolaka/netshoot -- sh
# Service(ClusterIP)로 호출
curl -m 2 -v http://<svc>.<ns>.svc.cluster.local:<port>/health
# Endpoints 확인
kubectl -n <ns> get ep <svc> -o yaml
# Pod IP로 직접 호출
curl -m 2 -v http://<pod-ip>:<targetPort>/health
- Pod IP 직접 호출은 되는데 ClusterIP가 안 되면 kube-proxy/IPVS/노드 커널 계층 문제로 좁혀집니다.
6-2) 노드에서 tcpdump로 드랍 지점 확인
# 노드에서(트래픽이 지나는 인터페이스 지정)
sudo tcpdump -ni any host <pod-ip> and port <targetPort>
요청이 들어오는지/응답이 나가는지/중간에 RST가 뜨는지로 rp_filter/conntrack/SG 문제를 추정할 수 있습니다.
안전한 전환/롤백 전략(운영 팁)
IPVS 전환은 “클러스터 전체를 한 번에” 바꾸기보다, 장애 시 영향도를 줄이는 방식이 좋습니다.
1) 노드 그룹 단위 카나리
- 새 노드 그룹(launch template/AMI)로 IPVS 커널 설정을 포함해 띄움
- 워크로드 일부만 스케줄(taint/toleration, nodeSelector)
- 서비스 오류율/지연/conntrack 사용량을 관찰 후 확장
2) 즉시 롤백 플랜
최악의 경우 iptables로 되돌리는 것이 가장 빠른 복구일 수 있습니다.
# kube-proxy ConfigMap에서 mode를 iptables로
kubectl -n kube-system edit cm kube-proxy
# mode: "iptables"
kubectl -n kube-system rollout restart ds/kube-proxy
다만 근본 원인(모듈/rp_filter/conntrack/SG)을 해결하지 않으면, iptables로 돌아가도 유사 장애가 다른 형태로 나타날 수 있습니다.
결론: IPVS 전환 후 통신 장애의 80%는 이 3가지
현장에서 가장 자주 맞닥뜨리는 “IPVS 전환 후 통신 장애”의 핵심 원인은 아래 3가지로 수렴합니다.
- 커널 모듈 누락(
ip_vs*,nf_conntrack,br_netfilter)로 IPVS 룰 생성 자체가 실패 - rp_filter로 인한 비대칭 라우팅 패킷 드랍(특정 노드/경로에서만 장애)
- conntrack 부족으로 인한 간헐 드랍/리셋 및 대규모 트래픽에서의 불안정
위 순서대로 점검하면 “서비스가 왜 안 붙는지”를 감이 아니라 증거로 좁힐 수 있고, 대부분은 kube-proxy 롤링 재기동까지 가지 않고도 해결됩니다. 만약 IPVS 전환과 함께 외부 HTTPS만 실패하거나 VPC 엔드포인트/NAT/DNS 같은 경계 구간이 의심된다면, 위에 링크한 네트워크 진단 글을 함께 참고해 전체 경로를 분해해 보세요.