IL-0049 Preply · 2020-02-28kubernetesnetworking
2020년 2월 28일 Preply 의 쿠버네티스 클러스터에서 일부 서비스의 DNS 가 26분 동안 부분적으로 멈췄다. 서비스 A, B, C 에서 이벤트 15000건이 유실됐다.
클러스터 부하가 낮아지자 CoreDNS-autoscaler 가 CoreDNS 파드를 3개에서 2개로 줄였다. 이때 kube-proxy 가 conntrack 테이블에서 사라진 CoreDNS 파드로 가는 옛 항목을 지우지 못했다. conntrack 은 리눅스 커널이 NAT 기록을 테이블에 담아 두는 기능이다. 커널은 같은 출발지 파드에서 같은 목적지로 가는 다음 패킷을 CPU 를 아끼려고 다시 변환하지 않고, 이 테이블에서 목적지 주소를 가져온다. 그래서 일부 서비스의 DNS 요청이 이미 없어진 파드로 계속 갔다.
당직 엔지니어들은 22시 39분에 서비스의 최신 릴리스를 되돌렸고, 22시 40분에 5xx 오류가 사라졌다. 포스트모템은 해결 경위를 이렇게 적었다. 클러스터의 정기 배포가 새 노드를 만들었고, CoreDNS-autoscaler 가 다시 파드를 늘리면서 conntrack 테이블이 자동으로 새로 쓰였다. 감지까지 4분, 대응 착수까지 21분, 해결까지 1분이 걸렸다.
팀은 진짜 근본 원인을 아직 모른다고 밝혔다. conntrack 의 특정 버그로 보인다고 했다. 운이 좋았던 점도 두 가지 적었다. 다른 배포가 우연히 CoreDNS-autoscaler 를 움직여 conntrack 테이블이 새로 쓰인 것, 그리고 장애가 모든 서비스로 번지지 않은 것이다.
Prometheus 모니터링이 서비스 A, B, C 에서 5xx 비율이 높아진 것을 잡아 당직자를 호출했다. 당직 엔지니어들은 22시 18분부터 VictorOps 호출을 받기 시작했다. Kibana 에서도 5xx 비율이 올라간 것이 보였다.
그보다 5분 앞선 22시 13분에 CoreDNS-autoscaler 가 CoreDNS 파드를 3개에서 2개로 줄였다. CoreDNS 로그에는 다음 줄이 남았다. I0228 20:13:53.507780 1 event.go:221] Event(v1.ObjectReference{Kind:"Deployment", Namespace:"kube-system", Name:"coredns", UID:"2493eb55-3dc0-11ea-b3a2-02bb48f8c230", APIVersion:"apps/v1", ResourceVersion:"132690686", FieldPath:""}): type: 'Normal' reason: 'ScalingReplicaSet' Scaled down replica set coredns-6cbb6646c9 to 2
같은 시각 kube-proxy 는 conntrack 항목을 지우지 못했다는 오류를 남겼다. E0228 20:13:53.795782 1 proxier.go:610] Failed to delete kube-system/kube-dns:dns endpoint connections, error: error deleting conntrack entries for UDP peer {100.64.0.10, 100.110.33.231}, error: conntrack command returned: ...
당직 엔지니어들은 22시 21분에 원인 조사를 시작했다. 22시 39분에 해당 서비스의 최신 릴리스를 되돌렸고, 22시 40분에 5xx 오류가 사라지며 상황이 안정됐다. 장애는 모든 서비스가 아니라 일부 서비스에만 나타났다.
원인 ? DNS·네트워크 장애
Prometheus 모니터링이 서비스 A, B, C 에서 5xx 비율이 높아진 것을 잡아 VictorOps 로 당직자를 호출했다. 포스트모템이 적은 감지 시간은 4분이다.
모니터링은 장애를 빨리 잡았고 대응도 빠르고 체계적이었다. 노드는 어떤 한도에도 닿지 않았다.
진짜 근본 원인은 아직 모른다. conntrack 의 특정 버그로 보인다. 팀이 정한 후속 조치는 모두 장애가 낳는 결과를 막는 것이지 근본 원인을 고치는 것이 아니다.
팀은 DNS 에서 문제가 날 수 있다는 것을 알고 있었지만 이 일을 우선해서 다루지 않았다.
같은 원인 · 공통 kube-proxy, conntrack 테이블
같은 원인 · 공통 CoreDNS
같은 원인 · 공통 conntrack 테이블
같은 원인 · 공통 conntrack 테이블