SMALL

트러블슈팅 10

ndots:5 한 줄이 클러스터를 무릎 꿇린 새벽

지난주 화요일 새벽 2시 47분, 슬랙 알림이 무더기로 떴다. P99 레이턴시 그래프가 평소 80ms 근처에서 600ms 위로 튕겨 올라가더니, API 5xx 비율이 0.1%에서 4%까지 치솟았다. 결제 트래픽이 한창 몰리는 시간대였다.처음엔 또 어디서 메모리가 새는 건가 싶었다. 근데 컨테이너 메모리는 멀쩡했고, CPU도 평소 수준이었다. 그러다 어떤 마이크로서비스 로그를 까보니 거의 모든 요청에 dial tcp: lookup api.stripe.com on 10.96.0.10:53: i/o timeout 같은 줄이 박혀 있었다. DNS였다.첫 의심: CoreDNS 파드가 죽었나당연한 수순으로 kubectl -n kube-system get pods -l k8s-app=kube-dns 부터 쳐봤다. 다..

IT/Kubernets 2026.06.26

새벽 3시, CoreDNS NXDOMAIN 폭주로 잠을 못 잤다

처음엔 외부 API를 의심했다새벽 3시 12분. 슬랙 알림이 한 번에 17개 쌓였다. P99 외부 API 호출 latency가 평소 80ms에서 4초까지 튀었다. 처음엔 SaaS 벤더 쪽 장애인가 싶었는데, 우리 쪽 다른 서비스들도 다 같이 느려지고 있었다. 멘탈이 한번 나가고, 노트북을 켰다.결론부터 말하면 CoreDNS NXDOMAIN 폭주였다. 솔직히 DNS 문제는 항상 의심해야 한다는 걸 머리로는 알았는데, 실제로 새벽에 당해보니 또 한 번 새겼다. 우리 팀이 운영하는 EKS 클러스터, 노드 38대, 워크로드 약 400개 정도 되는 규모다.알림 내용은 단순했다. httpClient.get 호출 P99가 폭증 중이라는 거. 외부 결제 SaaS 호출이 대부분이라 벤더 status 페이지부터 봤다. 다..

IT/기타 2026.06.20

pgbouncer transaction mode에서 prepared statement 깨진 새벽 사건

지난주 새벽에 또 깼다. 4시쯤 핸드폰이 미친 듯이 울리는데, 화면을 보니 prepared statement "S_42" does not exist 에러가 분당 수천 건씩 쌓이고 있었다. 결제 API 쪽이었는데, 그날따라 더 짜증났던 건 — 두 시간 전에 내가 직접 머지한 PR 때문이라는 게 거의 확실했기 때문이다.결론부터 말하면 pgbouncer transaction pooling 모드 + 새 JDBC 드라이버 조합이 문제였다. 근데 거기까지 가는 과정이 정말 길었다.새벽 4시, 일단 롤백부터운영 룰은 단순하다. 새벽에 깨면 일단 의심되는 배포부터 롤백. 두 시간 전 머지한 PR이 두 개 있었다 — 하나는 pgbouncer 버전 업(1.18 → 1.23), 다른 하나는 백엔드 서비스의 PostgreSQ..

IT/DB 운영 2026.06.17

노드 드레인이 안 끝나던 새벽, 범인은 PDB였다

지난 주말에 클러스터 노드 OS 패치 작업이 있었다. 24대짜리 워커 노드를 하나씩 cordon → drain → 재부팅 → uncordon 하는 흔한 작업이다. 자동화 스크립트도 있고, 평소엔 노드 한 대당 5분 정도면 끝난다. 그런데 그날따라 9번째 노드에서 kubectl drain 명령이 멈췄다. 30분이 지나도 진척이 없었다. 새벽 2시였고, 나는 졸린 눈으로 터미널을 노려보고 있었다.일단 진정하고 상태 확인부터drain 로그를 보니 이런 메시지가 반복되고 있었다.evicting pod default/payment-api-7c8d9-x4k2perror when evicting pods/"payment-api-7c8d9-x4k2p" -n default(will retry after 5s): Cann..

IT/Kubernets 2026.06.12

distroless 파드 디버깅, kubectl debug로 5초

상황운영 중인 파드가 한 개 있다. 베이스 이미지는 gcr.io/distroless/static:nonroot. 셸은커녕 ls도 없다. 그런데 갑자기 이 파드만 외부 API 호출이 실패하기 시작한다. DNS 문제인지, 라우팅 문제인지, 인증서 문제인지 확인하고 싶다. 파드를 재시작하면 증상이 사라질 수도 있으니 살아있는 상태에서 보고 싶다. 자, 어떻게 할까?이거 모르는 분 꽤 많더라. 어제 후배가 "프로덕션 파드에 들어가서 curl 좀 찍어보고 싶은데 distroless라서 kubectl exec가 안 먹힌다"라고 슬랙에 글 올린 거 보고 깜짝 놀랐다. kubectl debug가 GA 된 게 1.25 (2022년 후반) 인데, 2026년 지금까지도 의외로 안 쓰는 사람이 많은 것 같아서 짧게 정리한다...

IT/Kubernets 2026.05.28

Pod 시작이 느릴 때, fsGroupChangePolicy 한 줄만 바꿔보자

증상이런 경험 다들 한 번쯤 있을 거다. Pod가 Running까지 가는 데 2-3분, 심하면 5분 넘게 걸린다. 이벤트 찍어봐도 별다른 에러 없고, ImagePull도 끝났고, PV Attach/Mount도 정상 완료. 그런데 컨테이너가 시작을 안 한다. kubectl describe pod 해보면 그냥 조용히 멈춰 있다.이때 kubelet 로그를 보면 이런 라인이 줄줄이 찍히고 있을 가능성이 높다.SetVolumeOwnership ... took 142.3s범인은 fsGroup이다. SecurityContext에 fsGroup: 1000 같은 거 설정해두면, kubelet이 PV를 마운트할 때 그 안의 모든 파일을 chown/chmod로 훑는다. 파일이 10만 개면 10만 번. 그게 NFS나 EFS ..

IT/Kubernets 2026.05.19

CronJob 실패 로그가 증발한 사건

지난주 새벽의 작은 사고지난주에 작은 사고가 있었다. 큰 장애는 아니었는데, 디버깅하면서 내가 너무 기본값을 신뢰하고 있었다는 걸 깨달았다. CronJob failedJobsHistoryLimit 얘기다.상황은 이랬다. 데이터 동기화용 CronJob이 매 5분마다 도는데, 모니터링 대시보드에서 어느 새벽부터 실패 카운트가 슬슬 올라가고 있었다. 한 시간쯤 지나서 PagerDuty가 울렸고, 출근 전이라 자느라 못 봤다. 아침에 일어나서 보니 한 시간 동안 12번 실패한 상태였다.로그를 보러 갔는데당연히 kubectl logs부터 쳤다. Pod가 이미 사라진 상태. 그렇지, CronJob은 Job을 만들고, Job이 Pod를 만든다. Pod는 사라져도 Job 객체는 남아있어야 하니까 그쪽을 보자.$ kub..

IT/Kubernets 2026.05.15

PgBouncer transaction pooling, prepared statement 함정에서 빠져나온 이야기

지난주 화요일 오후, 모니터링 알람이 울렸다. PgBouncer 앞단의 connection 사용량이 평소 대비 3배 가까이 튀어 있었고, 어플리케이션 쪽 P99 레이턴시는 슬슬 200ms를 넘기고 있었다. 트래픽은 평소 수준. 이상한 점은 RDS Postgres의 active connection 수가 거의 변동이 없다는 거였다. 즉, 클라이언트 → PgBouncer 사이에서 뭔가 막혀 있다는 뜻이다.이번 글은 그날 밤 새벽 2시까지 잡고 있던 이 문제를 어떻게 추적했는지, 그리고 결국 prepared statement와 transaction pooling이 충돌하던 지점을 어떻게 풀어냈는지에 대한 기록이다. 결론부터 말하면, 우리가 두 달 전에 한 PgBouncer 버전 업그레이드가 진짜 원인이었다.처음..

IT/DB 운영 2026.05.14

Prometheus remote_write 큐가 메모리를 잡아먹은 새벽

지난 주말, 새벽 2시쯤 PagerDuty가 울렸다. central monitoring 클러스터의 Prometheus가 OOMKill로 재시작 루프를 돌고 있다는 알람이었다. 메모리 limit을 32Gi로 잡아둔 인스턴스인데, 이게 몇 분 만에 한계를 찍고 죽고 있었다. 멘탈이 좀 흔들렸다. 평소엔 14~16Gi 정도에서 안정적으로 돌던 녀석이었다.원인을 추적하다 보니 결국 remote_write 큐 동작에 대해 내가 잘못 알고 있었던 부분이 꽤 있었다. 이번 글은 그날 새벽 삽질의 기록이다.배경: 우리 팀의 metric pipeline우리는 Thanos 대신 Mimir로 1년 전쯤 옮겼고, 각 워크로드 클러스터의 Prometheus가 remote_write로 Mimir 게이트웨이에 메트릭을 밀어넣는 구..

IT/모니터링 2026.05.10

NodeLocal DNSCache 없이 버티다 conntrack에 발목 잡힌 새벽

지난주 화요일 새벽 2시 17분에 페이저가 울렸다. 결제 API의 P99 레이턴시가 1.2초를 찍고 있었다. 보통 80ms대로 노는 애가 갑자기 15배가 됐는데, 이게 가끔 한 번씩 튀고 끝나는 게 아니라 5분 동안 꾸준히 그 모양이었다. 멘탈이 살짝 나갔다. 결제는 트래픽 자체는 크지 않은데 도미노가 한번 시작되면 SLO 까먹는 속도가 가차 없는 구간이라.결론부터 적자면, 그날 밤 범인은 애플리케이션도, DB도, 네트워크 장비도 아니었다. CoreDNS와 conntrack이었다. 며칠 뒤 NodeLocal DNSCache를 깐 후로는 같은 증상이 안 났는데, 이 일을 글로 정리해두고 싶었다. 비슷한 패턴은 의외로 흔한 것 같아서.처음에 의심한 것들알람 받자마자 떠오른 후보는 셋이었다. 결제 DB의 락,..

IT/기타 2026.04.26
BIG