IL-0054 DevOps Hof · 2019-02-01 (게시일)kubernetesgcpnetworking
DevOps Hof 팀은 GKE 클러스터에 새 노드 풀을 만들고 옛 노드 풀의 워크로드를 옮기려고 옛 노드를 드레인했다. 드레인 도중 ingress-nginx 로 노출된 모든 서비스에 접속할 수 없게 됐다. 세 가지 동작이 겹친 결과였다.
첫째, GCP 용 ingress-nginx 배포 매니페스트는 기본으로 service.spec.externalTrafficPolicy 를 Local 로 둔다. 요청의 원래 클라이언트 IP 를 지키려는 설정으로, 트래픽을 받은 노드에 있는 엔드포인트로만 요청을 보낸다. 둘째, 쿠버네티스는 GCP 로드밸런서에 healthCheckNodePort 의 /healthz 를 호출하는 HTTP 헬스 체크를 만든다. externalTrafficPolicy 설정 때문에 이 헬스 체크는 서비스 엔드포인트가 없는 노드에서 일부러 실패한다. 여기서 서비스 엔드포인트는 ingress-nginx 파드다. 셋째, 쿠버네티스 서비스 컨트롤러는 Ready 이면서 스케줄 가능한 노드만 로드밸런서 백엔드에 넣는다. 드레인하려고 cordon 한 노드는 스케줄할 수 없으므로 백엔드에서 빠진다. 글쓴이는 이 동작이 마스터 서버를 로드밸런서에서 빼려는 것으로 이해했지만, cordon 한 일반 워커 노드에도 똑같이 적용된다.
그 결과 로드밸런서는 ingress-nginx 파드가 아직 없는 새 노드만 가리켰고, 그 노드들의 헬스 체크는 모두 실패했다. ingress-nginx 파드는 Pod Disruption Budget 문제로 옛 노드에서 축출되지 않은 채 남아 있었다. 이 클러스터의 인그레스 트래픽이 사실상 모두 끊겼다.
팀은 옛 노드에 남아 있던 nginx-ingress-controller 파드를 지웠다. 파드는 새로 Ready 상태가 된 노드에 다시 스케줄되었고 문제가 풀렸다.
GKE 클러스터에서 워크로드를 새 노드 풀로 옮기려고 옛 노드들을 드레인하던 중, 클러스터의 어떤 서비스에도 ingress-nginx 를 거쳐 접속할 수 없게 됐다.
팀은 ingress-nginx 의 LoadBalancer 서비스와 nginx-ingress-controller 파드 엔드포인트를 확인했다. LoadBalancer 서비스는 GCP 로드밸런서의 백엔드 풀 설정을 바꿔 새 노드만 가리키고 옛 노드는 더 이상 가리키지 않았다. 반면 nginx-ingress-controller 파드는 여전히 옛 노드에서 돌고 있었다. Pod Disruption Budget 문제로 이 파드들이 옛 노드에서 축출되지 않았다.
로드밸런서의 헬스 체크는 새 노드만 가리켰고, 새 노드에는 아직 ingress-nginx 파드가 없어서 헬스 체크가 모두 실패했다. 옛 노드로는 트래픽이 가지 않았다.
처음에 팀은 이것이 왜 문제가 되는지 의아했다. 보통은 트래픽이 어느 노드로 들어오든 kube-proxy 가 다른 노드에 있는 엔드포인트로 알아서 넘겨 주기 때문이다.
옛 노드를 드레인하던 중 클러스터의 어떤 서비스에도 ingress-nginx 를 거쳐 접속할 수 없는 것을 팀이 알아챘다.
–
트래픽에 영향을 줄 수 있는 변경을 하기 전에는 문서를 두 번 확인한다.
externalTrafficPolicy 가 Local 이면 kube-proxy 는 다른 노드로 트래픽을 넘기지 않고, 로드밸런서 헬스 체크는 엔드포인트가 없는 노드에서 실패한다. cordon 한 노드는 로드밸런서 백엔드에서 빠진다. 이 둘이 겹치면 인그레스 컨트롤러 파드가 cordon 한 노드에만 남아 있을 때 트래픽이 모두 끊긴다.
같은 원인 · 공통 인그레스 컨트롤러
같은 원인 · 공통 노드 풀
같은 원인 · 공통 인그레스 컨트롤러
같은 원인 · 공통 인그레스 컨트롤러