{"id":"IL-0110","org":"DFDS","date":"2024-03-13","docs":[],"title":{"en":"A Grafana Agent pod's high memory use and crash-looping Hangfire pods drove a Kubernetes node into system OOM and NotReady, twice in one day","ko":"Grafana Agent 파드가 메모리를 많이 쓰던 노드에 Hangfire 파드가 함께 올라가 시스템 OOM 으로 CrashLoopBackOff 를 반복했고, 노드가 응답을 멈추고 NotReady 가 됐다."},"domain":["kubernetes","aws"],"impact":{"scope":"Two Kubernetes nodes, one after the other, and the workloads on them; the Grafana Agent was down until 13:02","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Dev workloads mixed with production let one crash-looping dev container take down nodes that production also used, and a monitoring agent outside its dedicated node group added to the memory pressure. Scaling the suspect container back up before its owners had fixed it brought the failure back on the replacement node. The team also noted that action items from earlier post-mortems need follow-up, and that knowledge of useful CloudWatch metrics had not been shared, which made the diagnosis harder.","ko":"포스트모템에서 나온 후속 조치를 끝까지 챙겨야 한다. CloudWatch 에서 어떤 지표가 쓸모 있는지가 팀에 제대로 공유되지 않아 진단과 조사가 어려웠다."},"related":[],"sources":[{"url":"https://github.com/dfds/postmortems/blob/master/PM2024-001%20-%20Two%20Kubernetes%20nodes%20went%20into%20NotReady%20state.md","kind":"github","license":"unknown","archived":null}],"summary":{"en":"DFDS runs dev and production workloads on the same Kubernetes cluster on AWS. On 2024-03-13 a Grafana Agent pod used a large amount of memory on one node, and Hangfire pods of a dev container were scheduled to the same node. Those pods failed on system OOM, restarted and failed again in a spiral of CrashLoopBackOff until the whole node stopped responding and went NotReady. Unlike most of the monitoring stack, the Grafana Agent did not run on a dedicated node group.\n\nIn the morning the team marked the EC2 instance unhealthy so a new node started, cordoned and force-drained the NotReady node and terminated the instance, and declared the incident resolved at 12:10 while investigations continued. They then found the Grafana Agent still down because of a newly applied LimitRange, removed the LimitRange and restarted the agent. They found a correlation between the tenfold rise in EC2 network traffic, the RDS problems and the dev container, scaled the container to 0 and then back to its original 3 replicas, and the replacement node went NotReady at 15:03.\n\nThe second time, the team scaled the dev container to 0 again, a new node was added, and the team that owns the container was emailed and confirmed at 15:52 that it was working on a fix. The incident was closed at 09:20 UTC on 2024-03-14. The post-mortem gives 4 minutes to detection and 399 minutes to recovery.","ko":"DFDS 의 쿠버네티스 클러스터에서 2024-03-13 오전에 노드 하나가 NotReady 가 되어 새 노드로 교체됐다. 오후에는 그 새 노드에서 같은 일이 다시 일어났다.\n\n근본 원인은 한 노드에서 Grafana Agent 파드가 메모리를 많이 쓰고 있던 것이었다. 같은 노드에 Hangfire 파드가 배치되자 시스템 OOM 으로 CrashLoopBackOff 가 꼬리를 물었고, 결국 노드 전체가 응답을 멈췄다. 문제의 Hangfire 파드는 개발용 컨테이너였다. 개발 워크로드가 운영 워크로드와 섞여 있었고, 모니터링 스택 대부분과 달리 grafana-agent 는 전용 노드 그룹에서 돌지 않았다.\n\n첫 대응에서 팀은 EC2 인스턴스를 비정상으로 표시해 새 노드를 띄우고, 문제 노드를 cordon 하고 강제로 drain 한 뒤 종료했다. cordon 은 노드에 새 파드가 배치되지 않게 막는 것이고, drain 은 노드의 파드를 내보내는 것이다. 이후 조사에서 새로 적용한 LimitRange 때문에 Grafana Agent 가 13:02 까지 내려가 있었던 것을 찾아 고쳤다. 개발 컨테이너를 0개로 줄이자 트래픽이 정상으로 돌아왔지만, 3개로 되돌리자 15:03 에 새 노드가 다시 NotReady 가 됐다. 팀은 15:15 에 개발 컨테이너를 다시 0개로 줄이고 담당 팀에 메일을 보냈고, 15:52 에 개발팀이 문제를 확인하고 수정에 들어갔다. 탐지까지 4분, 복구까지 399분이 걸렸다."},"trigger":{"en":"Pods of a dev container that used Hangfire to trigger jobs failed with OOM and crash-looped on a node where a Grafana Agent pod was already using a lot of memory.","ko":"Hangfire 로 작업을 실행하는 개발 컨테이너가 Grafana Agent 가 메모리를 많이 쓰고 있던 노드에 배치됐고, 작업이 OOM 으로 실패하며 CrashLoopBackOff 를 반복했다."},"severity":"unknown","symptoms":["node-not-ready","crash-loop","oom-killed","monitoring-down"],"timeline":{"detected_after":"4m","resolved_after":"6h 39m"},"date_kind":"incident","detection":{"en":"A Slack alert fired two minutes after the node went NotReady and was picked up two minutes later; the second node's NotReady at 15:03 also raised a Slack alert.","ko":"10:03 UTC 에 Slack 으로 알림이 왔고, 10:05 에 알림을 확인하고 조사를 시작했다. 두 번째 노드는 15:03 에 Slack 알림이 왔고 15:09 에 확인했다. 탐지까지 걸린 시간은 4분이었다."},"components":["telemetry-agent","memory-limit","database"],"root_cause":"capacity","remediation":[{"text":{"en":"marked the EC2 instance unhealthy so a new node started","ko":"10:22 에 EC2 인스턴스를 비정상으로 표시해 새 노드를 띄웠다."}},{"text":{"en":"cordoned and force-drained the NotReady node and terminated its EC2 instance","ko":"10:30 에 NotReady 노드를 cordon 하고 강제로 drain 했고, 10:36 에 그 EC2 인스턴스를 종료했다."}},{"text":{"en":"removed the new LimitRange from the Grafana Agent namespace and restarted the Grafana Agent pod","ko":"13:02 에 네임스페이스에서 LimitRange 를 지우고 Grafana Agent 파드를 재시작했다."}},{"text":{"en":"scaled the dev container to 0 replicas, after which EC2 network traffic returned to normal","ko":"14시대에 문제의 개발 컨테이너를 0개로 줄였고, 몇 분 뒤 EC2 네트워크 트래픽이 정상으로 돌아왔다."}},{"text":{"en":"after the second NotReady, scaled the dev container to 0 replicas again and added a new node","ko":"두 번째 NotReady 뒤 15:15 에 개발 컨테이너를 다시 0개로 줄였고, 15:18 에 새 노드가 추가됐다."}},{"text":{"en":"emailed the team that owns the dev container, which confirmed it was working on a fix","ko":"15:19 에 개발 컨테이너를 맡은 팀에 메일을 보냈고, 15:52 에 그 팀이 문제를 확인하고 수정 중이라고 답했다."}}],"action_items":[{"text":{"en":"Move grafana-agent to the monitoring node group","ko":"grafana-agent 를 모니터링 노드 그룹으로 옮긴다."}},{"text":{"en":"Add alerts for when bandwidth across the cluster reaches a certain threshold","ko":"클러스터 전체 대역폭이 정해 둔 기준에 닿으면 알림을 보낸다."}},{"text":{"en":"Investigate whether memory limits can be set on the grafana-agent Helm chart","ko":"grafana-agent Helm 차트에 메모리 한도를 걸 수 있는지 조사한다."}},{"text":{"en":"Investigate grafana-agent memory usage","ko":"grafana-agent 의 메모리 사용량을 조사한다."}},{"text":{"en":"Ask Grafana support whether grafana-agent should use a PVC","ko":"grafana-agent 에 PVC 를 써야 하는지 Grafana 지원팀에 묻는다."}},{"text":{"en":"Consider pushing node logs to Loki with limited retention","ko":"보존 기간을 제한한 채 노드 로그를 Loki 로 보내는 방안을 검토한다."}},{"text":{"en":"Create a wiki page with common metrics and log queries to check when investigating issues with Kubernetes nodes","ko":"쿠버네티스 노드 문제를 조사할 때 확인할 자주 쓰는 지표와 로그 쿼리를 위키 페이지로 만든다."}}],"contributing":["blast-radius-too-wide","no-resource-limits","manual-action-worsened","monitoring-blind-spot"],"recurrence_of":null,"symptoms_text":{"en":"At 10:01 UTC on 2024-03-13 a Kubernetes node entered NotReady state, with CPU requests at 78% and memory requests at 82%. An alert fired in Slack at 10:03 and was picked up at 10:05. An attempt to SSH into the node at 10:13 failed because it was unresponsive; it started responding again at 10:19.\n\nCloudWatch showed a tenfold increase in EC2 network traffic leading up to the incident, and the Grafana Agent pod on the unhealthy node had high memory use. After the node was replaced, the Grafana Agent stayed down until 13:02 because of a LimitRange newly applied to its namespace.\n\nAt 13:49 the team concluded that a dev container using Hangfire to trigger jobs was failing with OOM and going into CrashLoopBackOff with new OOMs. At 13:55 they found problems on the RDS instance used by that container and a correlation between the increased EC2 network traffic, the RDS instance and the container. Scaling the container to 0 replicas brought network traffic back to normal within a few minutes, but after it was scaled back up to its original 3 replicas, the replacement node entered NotReady at 15:03.","ko":"2024-03-13 10:01 UTC 에 쿠버네티스 노드 하나가 NotReady 상태가 됐다. 그때 노드에 잡힌 requests 는 CPU 78%, 메모리 82% 였다. 10:03 에 Slack 으로 알림이 왔고, 10:05 에 알림을 보고 조사를 시작했다.\n\n10:13 에 노드에 SSH 로 들어가려 했지만 노드가 응답하지 않았고, 10:19 에야 다시 응답했다. 10:25 에 CloudWatch 에서 장애 직전까지 EC2 네트워크 트래픽이 열 배로 늘어난 것을 보았다. 10:30 에는 문제 노드에서 Grafana Agent 가 돌고 있었고 메모리를 많이 쓰고 있었다는 것을 확인했다.\n\n12:10 에 statuspage.io 로 해결을 발표한 뒤에도 조사를 이어갔다. 13:00 에 새로 적용한 LimitRange 때문에 Grafana Agent 가 여전히 내려가 있는 것을 발견했다. 13:49 에는 Hangfire 로 작업을 실행하는 개발 컨테이너가 OOM 으로 실패하고, OOM 이 날 때마다 CrashLoopBackOff 를 반복하고 있었다는 결론을 냈다. 13:55 에 이 개발 컨테이너가 쓰는 RDS 인스턴스에서 문제를 찾았고, EC2 네트워크 트래픽이 늘어난 것이 RDS, 개발 컨테이너와 맞물려 있다는 것도 찾았다.\n\n개발 컨테이너를 0개로 줄이자 몇 분 뒤 EC2 네트워크 트래픽이 정상으로 돌아왔다. 그런데 원래대로 3개로 되돌리자 15:03 에 새로 띄운 노드가 NotReady 가 되어 Slack 알림이 다시 왔다."},"updated_at":"2026-11-10T00:00:33.750995Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0110","org_slug":"dfds"}