IL-0195 Palark · 2023-06-07 (게시일)kubernetes
Palark 가 맡은 고객 클러스터에서 kube-apiserver 가 메모리를 다 써 버리고 죽기를 반복했고, 프로덕션 환경을 포함한 클러스터 전체에서 쿠버네티스 API 가 멈췄다. 팀은 먼저 컨트롤 플레인 노드에 CPU 와 메모리를 더했다. 처음 더한 양으로는 모자랐고, 한 번 더 늘린 뒤에야 API 가 안정됐다. 노드는 CPU 8개, 메모리 16 GB 에서 CPU 16개, 메모리 64 GB 로 커졌다.
원인은 Cilium 파드가 API 에 LIST 요청을 대량으로 보낸 것이었다. 클러스터에는 노드가 200개 넘게 있었고, 동시에 들어오는 요청이 API 서버의 메모리 사용량을 50 GB 까지 끌어올렸다. 부하가 API 서버 하나에 몰려 그 서버가 죽으면 요청이 다른 서버로 넘어가 같은 일이 반복됐다.
팀은 cilium-agent 가 API 에 동시에 보내는 요청 수를 제한하기로 했다. LIST 요청이 조금 느려져도 Cilium 동작에는 영향이 없다고 보았다. 쿠버네티스 1.20 부터 기본으로 켜져 있는 API Priority and Fairness 를 썼다. 이 기능은 API 서버로 들어오는 요청을 우선순위 수준으로 나누고, 수준마다 동시 처리 한도와 대기열을 둔다. 팀은 d8-cni-cilium 서비스 어카운트 그룹이 cilium.io API 그룹에 보내는 list 요청을 cilium-pods 라는 FlowSchema 로 묶었다. 이 요청은 assuredConcurrencyShares 5, 큐 16개, handSize 4, queueLengthLimit 50 으로 제한한 cilium-pods PriorityLevelConfiguration 이 맡아 처리하게 했다. 적용한 뒤에는 cilium-agent 를 재시작해도 메모리 사용량이 크게 변하지 않았고, 팀은 노드 자원을 원래 크기로 줄였다.
어느 평범한 아침, 기술 지원 엔지니어가 전화로 고객 클러스터가 프로덕션 환경까지 포함해 사실상 동작하지 않는다고 알려 왔다. 클러스터에 접속해 보니 kube-apiserver 가 메모리를 전부 써 버린 상태였다.
kube-apiserver 는 죽고, 재시작하고, 다시 죽기를 계속 반복했다. 그 결과 쿠버네티스 API 에 아예 접근할 수 없었다. 메모리 사용량 그래프는 50 GB 까지 올라갔다. 컨트롤 플레인 노드는 원래 CPU 8개, 메모리 16 GB 였다.
고객과 합의한 시험 시간에 cilium-agent 를 재시작하자 같은 흐름이 재현됐다. API 서버 하나에 부하가 몰렸고, 그 서버가 노드의 메모리를 다 먹은 뒤 죽었다. 그러면 요청이 다른 API 서버로 넘어갔고, 그 서버에서 같은 일이 되풀이됐다.
팀은 Grafana 대시보드에서 API 요청 수가 크게 늘어난 것을 보았다. Prometheus 에서 apiserver_request_total{verb=~"LIST", instance=~".*:.*", resource=~".*"} 로 요청을 인스턴스와 리소스별로 묶어 보니 LIST 요청 상당수가 Cilium 네트워크 정책 쪽에서 나오고 있었다. 감사 로그를 켜 두었기 때문에 문제의 요청을 하나하나 확인할 수도 있었다.
원인 용량 한계
기술 지원 엔지니어가 전화로 고객 클러스터가 사실상 동작하지 않는다고 알렸다. 요청을 보낸 쪽을 찾을 때는 Grafana 대시보드에서 API 요청 수가 급증한 것을 먼저 보았고, Prometheus 의 apiserver_request_total 을 인스턴스와 리소스별로 묶어 Cilium 네트워크 정책 쪽 LIST 요청을 찾았다. 감사 로그로 실제 요청도 확인했다.
특정 클라이언트의 요청을 API Priority and Fairness 의 별도 우선순위 수준에 묶어 두면, 그 클라이언트가 요청을 쏟아내도 사용자 요청이 밀리지 않고 API 서버도 버틴다. API 서버 전체의 동시 처리 한도는 --max-requests-inflight 기본값 400 과 --max-mutating-requests-inflight 기본값 200 을 더한 값이다. API 서버는 이 한도를 각 우선순위 수준의 assuredConcurrencyShares 비율대로 나누므로, 한 수준의 값을 올리면 다른 수준의 한도는 줄어든다. 로그 보기나 exec 같은 오래 걸리는 요청과 WATCH 요청은 이 한도에 걸리지 않는다. 큐 개수, queueLengthLimit, handSize 는 요청이 너무 느려지지 않으면서 갑작스러운 폭증에도 API 서버가 넘치지 않도록 실험으로 정해야 한다. 지켜볼 지표로는 apiserver_flowcontrol_rejected_requests_total, apiserver_current_inqueue_requests, apiserver_flowcontrol_request_execution_seconds 가 있다. Palark 는 이런 일을 이번 말고도 여러 번 겪었다.
IL-0204 Render 프랑크푸르트 클러스터에서 etcd 메모리 급증으로 컨트롤 플레인이 과부하에 걸렸고, 컨트롤 플레인 노드를 재부팅하자 그 위의 CoreDNS 가 다시 뜨지 못해 DNS 가 멈췄다.Render · 2024같은 원인 · 공통 쿠버네티스 API 서버
IL-0168 새 쿠버네티스 릴리스 뒤 많은 Kapsule 클러스터가 동시에 자동 업그레이드되면서 Kubernetes API 가 과부하로 OOM 이 났고, 새 노드 인증 방식의 재시도가 혼잡을 키워 노드가 Not Ready 가 됐다.Scaleway · 2024같은 원인 · 공통 쿠버네티스 API 서버
같은 원인 · 공통 쿠버네티스 API 서버
IL-0194 kube-apiserver 재시작 뒤 Vector DaemonSet 의 파드 list 요청이 한꺼번에 몰려 etcd 메모리가 세 배 가까이 늘고 마스터 노드가 연쇄적으로 재시작했다.Palark · 2023같은 원인 · 공통 쿠버네티스 API 서버
IL-0002 빌더 파드가 노드 한 대에 몰리자 kubelet 이 기본 API QPS 한도에 막혀 파드 상태를 늦게 갱신했고, CI 빌드가 AWS IAM 자격 증명을 받지 못해 실패했다Zalando · 2019같은 원인 · 공통 쿠버네티스 API 서버
https://incidentlib-mcp.benchlet.com/mcpAPI 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.
IL-0076 dex의 AuthRequest 리소스가 끝없이 쌓였고, 이를 치우려고 네임스페이스를 지우자 목록 조회 타임아웃과 재시도가 반복되며 쿠버네티스 마스터가 내려갔다Fullstaq · 2019같은 원인 · 공통 쿠버네티스 API 서버
IL-0075 클러스터가 EC2 인스턴스 약 290대로 커지자 노드마다 도는 Datadog 에이전트가 쿠버네티스 API 를 폴링하면서 API 서버가 CPU 와 메모리를 다 써 쿠버네티스 컨트롤 플레인을 쓸 수 없게 됐다.Civis Analytics · 2019같은 원인 · 공통 쿠버네티스 API 서버
같은 원인 · 공통 쿠버네티스 API 서버