사례4건
4건 중 1~4번째
IL-0070dask-gateway로 워커를 대량으로 띄우자 노드가 1분 만에 100대 늘었고, Prometheus가 메모리를 거의 다 쓰던 코어 노드에서 hub 파드를 비롯한 중요한 파드들이 축출되거나 재시작됐다2i2c2023- 증상
2023년 2월 1일 leap 클러스터의 prod 허브에서 노드가 대량으로 늘었고, hub 파드가 알 수 없는 이유로 재시작됐다. 사용자 지원 티켓도 들어왔다.
- 촉발
한 사용자의 dask-gateway 작업이 1분 사이에 dask-worker 노드를 100대쯤 늘렸고, Prometheus 는 노드 200대쯤의 지표 내보내기 대상을 수집하기 시작했다.
- 원인
- 구성 요소
- 기여 요인
- 감지
2i2c Freshdesk에 들어온 사용자 지원 티켓 414로 드러났다. 이후 엔지니어가 Grafana와 클러스터의 노드, event를 살폈다. 조사 내용은 같은 날 UTC+1 기준 저녁 8시에서 9시 사이에 이슈에 정리됐다.
- 후속 조치
- basehub에서 hub와 proxy 파드의 CPU와 메모리 요청을 넉넉히 설정한다. 이슈 #2127이다.
- Grafana의 OOMKiller 대시보드가 제대로 동작하게 고친다. 이슈 #2213이다.
- LEAP 클라우드 인프라를 공유 노드 구성으로 옮긴다. 이슈 #2209다.
- ingress-nginx와 Prometheus의 리소스 요청과 한도를 고친다. Prometheus 서버는 메모리 요청을 한도와 같게 맞춘다. 이슈 #2324다.
- Prometheus가 daskhub 워커 파드를 수집하도록 넣은 설정이 필요한지 다시 본다. 이슈 #2366이다.
- 교훈
Prometheus 서버처럼 메모리를 많이 쓰는 파드가 요청보다 훨씬 많이 쓰면 같은 노드의 중요한 파드가 축출된다. 노드가 한꺼번에 100대 늘면 Prometheus가 수집할 대상도 함께 늘어난다. hub와 proxy처럼 중요한 파드는 실제 사용량보다 요청을 넉넉히 잡아야 축출과 CPU 부족을 피할 수 있다. 쿠버네티스 event는 60분이 지나면 사라지므로, OOMKill 여부를 나중에 확인하려면 따로 기록해 두어야 한다.
IL-0205Google Cloud us-east1 의 SSD 영구 디스크 재고가 바닥나 GKE 클러스터 오토스케일러가 프로덕션 노드를 늘리지 못했고, API 디플로이먼트가 파드를 띄울 용량을 얻지 못했다.GitLab2021- 증상
2021-06-21 08:05 UTC 부터 API 의 Apdex 가 나빠지고 Rails 대기열이 늘어나는 추세가 보였다. Apdex 는 목표 시간 안에 끝난 요청의 비율로 사용자 만족도를 나타내는 지표다. 08:43 에 ahmad 가 Slack 에서 장애를 선언했고, 09:01 에 API 디플로이먼트가 비정상 상태이고, 노드를 늘려 파드 용량을 더할 수도 없다는 것을 확인했다.
- 촉발
GitLab 이 운영하는 GCP us-east1 리전에서 SSD 재고가 바닥난 상태였는데, 사용자 트래픽이 늘어 API 서비스가 노드를 늘려야 했다.
- 원인
- 구성 요소
- 기여 요인
- 감지
로그를 한참 뒤져서 찾았다. 클러스터 오토스케일러 오류는 일부 노드가 백오프 상태라 확장할 수 없다고만 했고, 인스턴스 그룹 수준 오류도 ZONE_RESOURCE_POOL_EXHAUSTED 뿐이어서 어떤 자원이 바닥났는지 알 수 없었다. 결국 GCP 지원팀이 SSD 재고 부족을 알려 주었다. 탐지까지 22시간이 걸렸고, 팀은 자원 가용성 알림이 있었다면 탐지와 진단을 앞당길 수 있었다고 보았다.
- 조치
- 09:55 에 pd-standard 디스크를 쓰는 노드 풀을 하나 더 만들었다.
- 10:37 에 새 노드 풀이 늘어나지 않자 API 부담을 덜려고 이 노드 풀을 세 존 모두에서 손으로 늘렸다.
- 13:42 에 배포가 막혀 있고 다른 워크로드도 같은 영향을 받고 있어서 pd-standard 디스크를 쓰는 새 노드 풀들을 올리기로 했다.
- 18:16 에 canary 시험에서 클러스터 오토스케일러가 새 노드 풀과 함께 동작하지 않자 프로덕션 배포를 막는다고 공지하고, 오토스케일러 문제로 Google 에 지원 케이스를 열었다.
- 18:26 에 남은 워크로드의 노드 풀과 nodeSelector 를 바꾸는 인프라 작업을 시작했다.
- pd-standard 노드 풀 위주로 하루 동안 운영하며 문제가 없는 것을 확인한 뒤 SSD 노드 풀을 정리해 없앴다.
- 후속 조치
- 쿠버네티스 서비스를 pd-standard 디스크로 옮겼다.
- 자원 고갈 오류를 지표로 수집한다.
- 교훈
장애를 수습하는 도중 다른 버그를 만나 대응 전체가 느려졌다. 팀에는 클라우드 자원 가용성을 감시할 수단도, 자원을 미리 예약해 둘 수단도 없었다. 워크로드는 pd-ssd 대신 pd-standard 디스크에서도 문제없이 도는 것으로 보였다.
IL-0039CentOS 저장소 재구성으로 kops nodeup 에 하드코딩된 container-selinux 패키지 주소가 깨져 새 워커 노드가 클러스터에 합류하지 못했다FREE NOW2019- 증상
Prelive 클러스터에 배포하던 개발자들이 #ask-platform 슬랙 채널에 배포가 실패한다고 알렸다. 16:00 에 첫 제보가 왔고 16:06 에 두 번째 제보가 왔다.
- 촉발
CentOS 저장소가 재구성되면서 container-selinux 패키지의 고정 다운로드 주소를 더는 쓸 수 없게 됐다. kops 는 nodeup 에 이 주소를 하드코딩해 두었고, docker-ce 를 실행하려면 이 패키지가 필요했다.
- 원인
- 구성 요소
- 기여 요인
- 감지
팀은 개발자들이 배포가 실패한다며 #ask-platform 슬랙 채널에 도움을 요청하면서 장애를 알게 됐다. 조사를 시작하자 배포 실패의 원인이 클러스터 용량 부족이라는 것이 빠르게 드러났다.
- 조치
- Prelive 노드에서 패키지를 손으로 내려받아 부트스트랩을 끝내고 노드를 클러스터에 합류시켰다.
- 클러스터 AMI 를 Amazon Linux 2 에서 Debian 으로 바꿔 Prelive 에서 확인한 뒤 모든 클러스터에 적용했다.
- 후속 조치
- 노드가 클러스터에 합류하지 못하는 상황을 알려 주는 알림을 만든다. cluster-autoscaler 가 이 정보를 갖고 있을 수 있다.
- 노드 시작에 필요한 외부 의존성을 문서로 정리하고 줄일 방법을 찾는다.
- kops 가 이 문제를 고치면 AMI 를 Amazon Linux 2 Minimal 로 되돌린다.
- 클러스터 노드 문제 해결 문서를 보강해, 부트스트랩 중에 무슨 일이 일어나고 로그가 어디에 남는지 적는다.
- 교훈
kops 와 Jenkins 로 클러스터 변경을 적용하는 흐름은 잘 동작했다. 조사를 시작하자 배포 실패의 원인이 클러스터 용량 부족이라는 것이 빠르게 드러났다. 일부 오토스케일링 그룹의 워커 인스턴스 수와 쿠버네티스에 등록된 워커 노드 수가 오랫동안 달랐는데도 아무도 알아채지 못한 것은 잘못이었다. 문제가 이어지는 동안 운영 환경의 스팟 인스턴스가 대량으로 종료되지 않은 것과 업무 시간에 발견한 것은 운이 좋았다.
IL-0040비운영 쿠버네티스 클러스터에 Helm 차트를 한꺼번에 설치하자 작은 gp2 루트 볼륨의 IOPS 가 바닥나, 워커 노드 세 대에서 kubelet 이나 Docker 가 내려가 세 대 모두 NotReady 가 됐다Saltside2017- 증상
SRE 팀장이 애플리케이션 Helm 차트를 고친 뒤 자기 머신에서 CI 과정을 돌렸다. watch kubectl get pods 로 지켜보니 파드가 모두 Running 이 되었는데, 그중 일부가 다시 Pending 으로 바뀌었다. 그는 저절로 풀릴 일시적인 문제라고 보고 회의에 들어갔다.
- 촉발
CI 과정을 로컬에서 돌려 시장 네 곳의 Helm 차트를 비운영 클러스터에 한꺼번에 설치했다. 그 결과 t2.medium 워커 노드 세 대가 여러 컨테이너의 이미지를 동시에 받고 컨테이너를 동시에 만들었다.
- 원인
- 구성 요소
- 기여 요인
- 감지
담당자가 CI 과정을 돌리며 watch kubectl get pods 로 지켜보다가 Running 이던 파드가 Pending 으로 바뀌는 것을 보았다. 두 시간 뒤 Unknown 상태의 파드를 보고서야 내부에서 무언가 확실히 잘못됐다고 판단했다. 워커 노드 세 대가 모두 NotReady 였지만 어떤 모니터링도 이를 잡지 못했다.
- 조치
- 워커 노드 세 대를 종료하고 오토스케일링 그룹이 새 인스턴스를 띄우게 했고, 약 10분 뒤 클러스터가 정상으로 돌아왔다.
- 후속 조치
- 비운영 AWS 계정과 DataDog 의 연동 문제를 고쳐 지표가 들어오게 하고, 그 지표를 보며 설치 과정을 다시 돌렸다.
- 워커 노드의 루트 EBS 볼륨을 20GB 에서 120GB 로 늘렸다.
- ruby:2.4, alpine:3.2 같은 공통 베이스 이미지 안에서 sleep 루프만 도는 DaemonSet 을 배포해 노드에 이미지를 미리 받아 두었다. kops 가 사용자 훅을 지원할 때까지 쓰는 임시 방편이다.
- 쿠버네티스의 계층마다 할당 한도를 다르게 설정한다.
- tiller 가 크래시 루프에 빠지면 차트 설치와 업그레이드로 수정을 배포할 수 없으므로 tiller 고가용성을 Helm 팀과 논의한다.
- 새로 만드는 파드 수를 조절할 방법을 찾는다.
- 교훈
평소 하던 애플리케이션 배포만으로도 클러스터가 무너질 수 있었다. 워커 노드를 종료하는 방법은 효과가 있었지만 파드를 다른 노드로 옮기지 않으므로 운영 환경에서는 고객이 서비스를 못 쓰게 된다. 그래서 이런 장애의 표준 절차가 될 수 없다. 노드 상태, 파드 단계, 노드 리소스 지표가 없으면 이런 장애를 알아채지 못한다. kops 의 기본 20GB gp2 루트 볼륨은 IOPS 와 디스크 공간이 모두 모자랐다. 새로 만드는 파드 수를 조절할 수단이 있으면 문제를 풀지는 못해도 위험을 줄일 수 있고, 무언가 잘못됐을 때 제 손으로 클러스터를 마비시키는 일을 막을 수 있다.
이 4건에서 가장 많이 나오는 구성 요소: 노드 풀, 클러스터 오토스케일러. kubegap 은 Claude Code 나 Codex 에서 쿠버네티스 클러스터를 읽기만 하며 이런 틈을 점검합니다. 점검 항목의 근거는 이 라이브러리와 같은 공개 보고서입니다.