{"id":"IL-0070","org":"2i2c","date":"2023-02-01","docs":["https://github.com/2i2c-org/infrastructure/issues/2126","https://github.com/2i2c-org/infrastructure/issues/2127","https://github.com/2i2c-org/infrastructure/issues/2213","https://github.com/2i2c-org/infrastructure/issues/2209","https://github.com/2i2c-org/infrastructure/issues/2324","https://github.com/2i2c-org/infrastructure/issues/2366"],"title":{"en":"Critical pods on core nodes evicted when Prometheus began scraping about 200 nodes after a dask-gateway scale-up","ko":"dask-gateway로 워커를 대량으로 띄우자 노드가 1분 만에 100대 늘었고, Prometheus가 메모리를 거의 다 쓰던 코어 노드에서 hub 파드를 비롯한 중요한 파드들이 축출되거나 재시작됐다"},"domain":["kubernetes","observability"],"impact":{"scope":"prod hub of the leap cluster restarted; critical pods on core nodes evicted","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Prometheus load grows with the number of nodes, so a burst of autoscaled nodes can push a nearly full core node over the edge and evict the pods that matter most. Core pods that request 10m of CPU get a tenth of the CPU share of busy neighbours that request 100m. Kubernetes events expire after an hour, so evidence of OOM kills needs a dashboard that keeps it.","ko":"Prometheus 서버처럼 메모리를 많이 쓰는 파드가 요청보다 훨씬 많이 쓰면 같은 노드의 중요한 파드가 축출된다. 노드가 한꺼번에 100대 늘면 Prometheus가 수집할 대상도 함께 늘어난다. hub와 proxy처럼 중요한 파드는 실제 사용량보다 요청을 넉넉히 잡아야 축출과 CPU 부족을 피할 수 있다. 쿠버네티스 event는 60분이 지나면 사라지므로, OOMKill 여부를 나중에 확인하려면 따로 기록해 두어야 한다."},"related":[],"sources":[{"url":"https://raw.githubusercontent.com/2i2c-org/incident-reports/main/reports/2023-02-01-daskhub-induced-evictions.md","kind":"github","license":"unknown","archived":null}],"summary":{"en":"2i2c runs JupyterHub with dask-gateway for the LEAP community. On 1 February 2023 one user's dask-gateway workload scaled the cluster by about 100 nodes in about a minute. Prometheus ran on one of the four core nodes next to the hub and already requested most of that node's memory. The incident report's author believes that various critical pods on the core nodes were evicted when Prometheus started scraping metrics exporters on about 200 nodes. The hub pod restarted.\n\nThe notes written during the incident give two possible reasons for the hub restart: eviction under memory pressure on the node shared with Prometheus, or a hub that stopped responding, perhaps starved of CPU with a 10m request, and was restarted after its liveness probe failed 30 times in a row. The report adds that the dask scheduler pod would likely, though not certainly, also hit resource limits with that many workers. No single cause was proven, partly because the events had expired before an OOM kill could be checked.","ko":"2i2c가 운영하는 leap 클러스터의 prod 허브에서 일어난 일이다. 사후 보고서는 Prometheus가 노드 약 200대의 메트릭 익스포터를 수집하기 시작하면서 코어 노드에 있던 중요한 파드들이 축출됐다고 본다. Prometheus 서버는 hub 파드와 같은 코어 노드에서 노드 메모리를 거의 다 쓰고 있었다. 보고서 작성자는 이것이 자기 판단이라고 밝혔다. 또 워커가 이만큼 많으면 dask 스케줄러 파드도 리소스 한계에 부딪혔을 가능성이 크지만 확실하지 않다고 덧붙였다.\n\n보고서는 후속 개선으로 이슈와 PR 다섯 개를 연결했다. hub와 proxy 파드의 CPU와 메모리 요청을 넉넉히 잡는 일, OOMKiller 대시보드를 고치는 일, LEAP 인프라를 공유 노드로 옮기는 일, ingress-nginx와 Prometheus의 요청과 한도를 고치는 일, dask 워커 파드를 Prometheus가 수집하는 설정이 필요한지 다시 보는 일이다."},"trigger":{"en":"A user's dask-gateway workload added about 100 dask-worker nodes within a minute, and Prometheus started scraping the metrics exporters on about 200 nodes.","ko":"한 사용자의 dask-gateway 작업이 1분 사이에 dask-worker 노드를 100대쯤 늘렸고, Prometheus 는 노드 200대쯤의 지표 내보내기 대상을 수집하기 시작했다."},"severity":"unknown","symptoms":["pods-evicted","pod-pending"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"incident","detection":{"en":"A user support ticket (2i2c Freshdesk ticket 414) about the leap hub; the engineer then looked at Grafana and the cluster's nodes and events.","ko":"2i2c Freshdesk에 들어온 사용자 지원 티켓 414로 드러났다. 이후 엔지니어가 Grafana와 클러스터의 노드, event를 살폈다. 조사 내용은 같은 날 UTC+1 기준 저녁 8시에서 9시 사이에 이슈에 정리됐다."},"components":["prometheus","node-pool"],"root_cause":"capacity","remediation":[],"action_items":[{"text":{"en":"Configure CPU and memory requests for the hub and proxy pods (#2127; at least 100m CPU was proposed)","ko":"basehub에서 hub와 proxy 파드의 CPU와 메모리 요청을 넉넉히 설정한다. 이슈 #2127이다."}},{"text":{"en":"Make the Grafana OOMKiller dashboard work (#2213)","ko":"Grafana의 OOMKiller 대시보드가 제대로 동작하게 고친다. 이슈 #2213이다."}},{"text":{"en":"Move LEAP cloud infrastructure to shared nodes (#2209)","ko":"LEAP 클라우드 인프라를 공유 노드 구성으로 옮긴다. 이슈 #2209다."}},{"text":{"en":"Update resource requests and limits, mainly for ingress-nginx and Prometheus (#2324)","ko":"ingress-nginx와 Prometheus의 리소스 요청과 한도를 고친다. Prometheus 서버는 메모리 요청을 한도와 같게 맞춘다. 이슈 #2324다."}},{"text":{"en":"Decide whether Prometheus should scrape dask worker pods (#2366)","ko":"Prometheus가 daskhub 워커 파드를 수집하도록 넣은 설정이 필요한지 다시 본다. 이슈 #2366이다."}}],"contributing":["no-spare-capacity","blast-radius-too-wide","monitoring-blind-spot"],"recurrence_of":null,"symptoms_text":{"en":"The hub pod of the prod JupyterHub on the leap cluster (leap.2i2c.org) restarted unexpectedly during a large node scale-up, and a user opened a support ticket. The ingress-nginx and proxy pods kept running.\n\nWithin about a minute roughly 100 nodes were added, probably along with 100 or more dask-worker pods. The dask workers' scheduling events read: `0/126 nodes are available: 14 node(s) didn't match Pod's node affinity/selector, 23 Insufficient cpu, 24 Insufficient memory, 6 node(s) had untolerated taint {node.kubernetes.io/network-unavailable: }, 9 node(s) had untolerated taint {hub.jupyter.org_dedicated: user}, 96 node(s) had untolerated taint {node.kubernetes.io/not-ready: }.`\n\nThe core node with the hub also ran support-prometheus-server, which requested 3 CPU and 20Gi of memory; the node had 88% of its CPU and 93% of its memory requested, and memory limits at 124%. The engineer could not confirm an OOM kill with `kubectl get event -A | grep OOM`, because the API server keeps events for only 60 minutes. Grafana showed the hub's memory steady, so a second theory was that the hub became unresponsive and its liveness probe restarted it; the hub and proxy pods requested only 10m of CPU.","ko":"2023년 2월 1일 leap 클러스터의 prod 허브에서 노드가 대량으로 늘었고, hub 파드가 알 수 없는 이유로 재시작됐다. 사용자 지원 티켓도 들어왔다.\n\ningress-nginx 파드와 proxy 파드는 오래 문제없이 돌고 있었지만 hub 파드는 재시작돼 AGE가 60m이었다. hub 파드가 있던 코어 노드 4대 가운데 두 번째 노드에는 support-prometheus-server 파드가 메모리 요청 20Gi, 한도 22Gi로 떠 있었다. 이 노드의 메모리 요청 합계는 93%, 한도 합계는 124%였다. hub 파드는 CPU 요청 10m, 메모리 요청 128Mi로 떠 있었다.\n\n1분 사이에 노드 100대가 추가됐고, dask-worker 파드에는 FailedScheduling 경고가 쌓였다. 그중 하나는 \"0/126 nodes are available: 14 node(s) didn't match Pod's node affinity/selector, 23 Insufficient cpu, 24 Insufficient memory, 6 node(s) had untolerated taint {node.kubernetes.io/network-unavailable: }, 9 node(s) had untolerated taint {hub.jupyter.org_dedicated: user}, 96 node(s) had untolerated taint {node.kubernetes.io/not-ready: }.\" 였다.\n\n조사한 엔지니어는 kubectl get event -A | grep OOM 으로 OOMKill 여부를 확인하려 했지만, API 서버가 event를 보관하는 60분이 이미 지나 확인하지 못했다. 처음에는 노드 메모리가 부족해 hub 파드가 축출됐다고 봤다. 그런데 hub 파드의 메모리 사용량은 일정했고 응답만 없었다. 그래서 5분 동안 응답이 없어 livenessProbe가 30번 연속 실패했고, 그 때문에 재시작됐을 수도 있다고 봤다. CPU 요청이 10m이라 CPU를 충분히 받지 못했을 가능성도 의심했다."},"updated_at":"2026-11-10T00:00:39.405912Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0070","org_slug":"2i2c"}