IL-0440 Cybozu · 2024-08-20 (게시일)kubernetesnetworking
파드가 보낸 DNS 쿼리 패킷이 노드에서 버려져 클러스터 내부 서비스의 이름 조회가 no such host 와 i/o timeout 으로 자주 실패했다
사이보즈의 Cloud Platform 팀은 Neco 라는 쿠버네티스 플랫폼을 운영한다. 클러스터 네트워크에는 주로 Cilium 을 쓰고, 일부 용도를 빼면 오버레이 네트워크를 쓰지 않는다. 파드의 DNS 조회는 노드마다 도는 캐시 DNS 서버 node-dns 를 먼저 거치고, 캐시에 없으면 클러스터 안의 권한 DNS 서버 cluster-dns 로 간다. node-dns 는 Unbound 이고 cluster-dns 는 CoreDNS 다.
MySQL 클러스터 감시 애플리케이션은 파드 하나에서 초당 1만 5천 패킷쯤을 보냈다. 파드가 보낸 패킷은 파드에 연결된 veth 인터페이스를 지나 CPU 의 backlog 큐에 들어간 뒤 호스트 쪽 veth 로 넘어간다. backlog 큐의 길이를 정하는 커널 파라미터 net.core.netdev_max_backlog 는 노드에서 기본값 1000 이었다. 큐가 가득 차자 패킷이 버려졌다. 버려진 패킷에 DNS 쿼리 패킷이 섞여 있어서 애플리케이션에 no such host 와 i/o timeout 오류가 났다.
dctest 는 데이터센터 구성을 VM 으로 통째로 가상화한 환경이다. 팀은 dctest 에 이번 장애와 비슷한 빈도로 패킷을 보내는 Go 프로그램을 배포해 1시간쯤 돌렸다. 그러자 /proc/net/softnet_stat 에서 CPU 코어 8 과 9 에 각각 790개와 183개의 드롭이 재현되었다. perf 로 skb:kfree_skb 이벤트를 기록하자 드롭 이유가 CPU_BACKLOG 로 나왔다. RPS flow limit 을 끈 환경이었으므로 backlog 큐가 가득 찬 것이 원인임을 다시 확인했다. 팀은 netdev_max_backlog 를 늘리고 softnet 알림과 그 런북을 마련했다. 이 조치는 근본 대책이 아니어서, veth 를 netkit 으로 바꾸는 방안을 다음에 검증하기로 했다.
- 심각도
- –
- 영향 범위
- Name resolution of cluster Services from a MySQL cluster monitoring application failed intermittently
- 영향 사용자
- –
- 지역
- –
- 감지까지
- –
- 복구까지
- –
증상
파드 안의 애플리케이션이 초당 수백 건씩 클러스터 내부 서비스의 이름을 조회하자 no such host 와 i/o timeout 오류가 자주 났다. 쿠버네티스 플랫폼을 쓰는 팀은 클러스터의 DNS 서버에 성능 문제가 있다고 보고 Cloud Platform 팀에 문의했다.
오류가 난 애플리케이션은 MySQL 클러스터를 감시하는 프로그램이었다. 이 프로그램은 매초 세션을 새로 만들어 MySQL 클러스터에 연결하고 SQL 쿼리가 제대로 실행되는지 확인한다. 감시하는 MySQL 클러스터 수가 늘어난 뒤부터 이름 조회 오류가 잦아졌다.
애플리케이션 로그에는 "write check failed" 메시지와 함께 "ping failed: dial tcp: lookup moco-1: i/o timeout" 오류가 찍혔다. 같은 시각 node-dns 인 Unbound 의 로그에서는 moco-1.default.svc.cluster.local. 조회 기록 사이가 10초쯤 비어 있었다. 애플리케이션의 조회가 node-dns 에 기록되지 않은 때와 타임아웃이 난 때가 겹쳤고, 다른 시간대의 로그에서도 같은 일이 보였다.
팀은 처음에 node-dns 와 cluster-dns 의 성능을 의심하고 메트릭과 로그를 봤다. 두 DNS 서버는 요청을 정상으로 처리하고 있었고, 실제로 있는 도메인을 NXDOMAIN 으로 응답하지도 않았다. 그래서 애플리케이션과 node-dns 사이 경로에서 패킷이 사라진다고 보고 네트워크를 조사했다.
cAdvisor 의 container_network_transmit_packets_dropped_total 에서는 파드가 송신 중에 버린 패킷이 초당 100개쯤 나타났다. Node exporter 의 node_softnet_dropped_total 도 늘고 있었다. 이 지표는 커널이 패킷을 CPU 의 backlog 큐에 넣으려 할 때 큐가 가득 차서 버린 패킷 수다.
moco-1 을 조회하면 검색 도메인을 붙인 쿼리 다섯 개가 나간다. moco-1.default.svc.cluster.local 쿼리만 버려지고 나머지 쿼리가 node-dns 에 닿으면, 나머지 쿼리는 모두 NXDOMAIN 을 받으므로 애플리케이션은 no such host 를 냈다. 다섯 쿼리가 모두 버려지면 응답이 오지 않아 i/o timeout 이 났다.
원인
- 촉발
- MySQL 클러스터 감시 애플리케이션이 감시하는 클러스터 수가 늘어났고, 그 뒤부터 이름 조회 오류가 잦아졌다.
감지
Cloud Platform 팀은 쿠버네티스 플랫폼을 쓰는 팀에게서 클러스터 DNS 서버에 성능 문제가 있다는 문의를 받고 알게 됐다.
조치
- 커널 파라미터 net.core.netdev_max_backlog 값을 늘렸다.
- softnet 지표에 알림을 설정했다.
- softnet 알림에 대응하는 런북을 마련했다.
후속 조치
- veth 인터페이스를 netkit 인터페이스로 바꿔 파드의 송신 패킷이 backlog 큐를 거치지 않고 물리 장치로 바로 가게 하는 방안을 검증한다. netkit 은 리눅스 커널 6.7 에 들어온 가상 네트워크 장치이고, Cilium 1.16 부터 쓸 수 있다.
교훈
netdev_max_backlog 를 늘리고 softnet 알림과 런북을 두면 같은 장애가 덜 나고, 나더라도 일찍 알아챌 수 있다. 다만 값을 늘리는 것은 근본 대책이 아니어서, 더 많은 패킷을 보내는 파드가 배포되면 backlog 큐가 다시 차고 패킷이 버려질 수 있다.
출처
참고 문서
관련 사례
IL-0048대형 EKS 클러스터에서 CoreDNS 가 VPC DNS 리졸버로 보내는 질의가 링크 로컬 트래픽의 초당 1024 패킷 한도에 걸려 DNS 조회가 간헐적으로 타임아웃됐다.unknown · 2025같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0312max_connections 를 올리려고 재시작한 주 PostgreSQL 데이터베이스가 다시 올라오지 않아 Gadget 의 모든 앱 요청이 멈췄다Gadget · 2024같은 원인 · 공통 리눅스 커널
같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0445EKS 로 옮기던 레거시 시스템에서 conntrack 테이블이 넘쳐 연결이 끊겼고, 이어 CoreDNS 파드가 축출될 때와 node-local-dns 를 넣은 뒤에 DNS 오류가 났다Chatwork · 2021같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0176시계열 급증으로 호스트 메모리가 바닥나자 oom_score_adj 999 를 받은 Prometheus 컨테이너가 커널 OOM Killer 에게 먼저 죽어 CrashLoopBackOff 에 빠졌다.LINE · 2020같은 원인 · 공통 리눅스 커널
같은 원인 · 공통 리눅스 커널
IL-0033kube-dns 파드 사이의 트래픽 불균형과 DNS 초당 패킷 한도 때문에 외부 DNS 조회가 많은 여러 서비스의 지연 시간이 20초까지 늘었다Airbnb · 2019같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
IL-0064CPU 를 많이 쓰는 파드가 Google Cloud 노드 하나에 몰려 노드가 커널 패닉으로 죽었고, 다시 배치된 파드가 다음 노드를 또 죽이며 웹사이트와 API 가 멈췄다.Moonlight · 2019같은 원인 · 공통 리눅스 커널
같은 원인 · 공통 리눅스 커널
같은 원인 · 공통 클라이언트 쪽 DNS 리졸버와 캐시
내 클러스터에도 있는지 확인하기
AI 도구와 스크립트용
- 이 사례의 JSON: https://incidentlib-api.benchlet.com/cases/IL-0440
- 가장 비슷한 사례들: https://incidentlib-api.benchlet.com/cases/IL-0440/similar
- MCP 서버(Streamable HTTP, 키 없음):
https://incidentlib-mcp.benchlet.com/mcp
API 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.