운영 중이던 쿠버네티스 클러스터에서 특정 노드가 갑자기 NotReady 상태로 전환되는 장애가 발생했다.
일반적으로 노드 장애는 kubelet 다운이나 자원 고갈을 의심하기 마련이다.
하지만 이번 케이스는 로그 분석 결과, 노드가 아닌 etcd의 성능 저하가 나비효과를 일으켜 발생한 사건이었다.
이 글에서는 etcd 지연 → apiserver 응답 불가 → kubelet 갱신 실패로 이어지는 장애의 인과관계를 실제 로그 패턴과 함께 살펴본다.
이전 글인 "Kubernetes Node Life Cycle - 노드의 생명주기" 밀접한 글이므로 이전 글을 확인하고 오시면 더 좋습니다.
Kubernetes Node Life Cycle - 노드의 생명주기
쿠버네티스에서 노드 헬스 체크(Node Health Check)는 클러스터의 안정적인 운영을 보장하는 메커니즘이다.이 글에서는 두 가지 개념을 톺아본다.노드 헬스 체크의 전반적인 구조와 개념실제로 어떤
mgujob.tistory.com
(공식 사이트에서 발췌한 내용을 기반으로 작성하였으나, 명확하지 않은 부분은 경험을 토대로 작성하였습니다. 이는 정확한 정보가 아닐 수 있음을 알려드립니다.)
참고 링크
광고 클릭은 큰 힘이 됩니다!
ETCD "wal sync: duration" error. · Issue #10414 · etcd-io/etcd
Hello, We are using kubernetes version 10.5 and etcd version 3.3.3. We are facing "wal sync duration" issue in etcd. Status of our etcd cluster is continiously changing from healthy to unhealthy an...
github.com
Performance
Understanding performance: latency & throughput
etcd.io
Node NotReady
"멀쩡히 살아있는 노드가 왜 죽은 것으로 판정되었을까?"
증상
특정 노드의 상태가 NotReady로 변경됨. Node Lease 및 Status 업데이트가 중단됨.
그러나 노드 자체의 리소스(CPU/Mem)는 여유가 있었고, OS 및 네트워크도 정상이었다.
단순히 노드 문제가 아니였고 로그를 시간 순서대로 확인했다.
장애는 아래와 같이 3단계의 연쇄 작용으로 일어났다.
1단계: I/O 병목 (Root Cause)
"모든 사단은 스토리지 I/O 지연에서 시작되었다."
가장 먼저 발견된 이상 징후는 etcd 로그였다. etcd는 디스크 쓰기 성능에 매우 민감한데, 당시 디스크 I/O가 느려지면서 동기화에 실패하고 있었다.
로그 패턴
Nov 10 16:30:44 etcd: sync duration of 2.941617046s, expected less than 1s
- sync duration 지연: 데이터 동기화에 1초 미만이 소요되어야 하는데, 약 3초가 걸렸다. 이는 전형적인 디스크 지연 혹은 스토리지 부하 증상이다.
Nov 10 16:30:45 etcd: read-only range request “key:/registry/health” ... took too long (1.6s) ... context canceled
- Health Check 실패: etcd가 자기 자신의 상태(
/registry/health)를 확인하는 요청조차 1.6초가 걸리다가 타임아웃(context canceled)이 발생했다.
2단계: kube-apiserver 전이
"etcd가 멈추니, apiserver도 말을 잃었다."
etcd가 응답을 주지 못하자, 이를 바라보고 있는 kube-apiserver도 덩달아 오류를 뱉기 시작했다.
주요 로그 패턴
Nov 10 16:30:45 etcd: WARNING: grpc: Server.processUnaryRPC failed to write status: connection error: desc = “transport is closing”
- gRPC 연결 끊김: apiserver와 etcd 사이의 gRPC 통신이
transport is closing에러와 함께 끊어졌다. - 이 시점부터 apiserver는 들어오는 API 요청(kubectl, kubelet 등)을 처리하려고 해도, 백엔드 DB인 etcd가 응답하지 않으니 타임아웃을 리턴하거나 연결을 강제로 종료하게 된다.
3단계: kubelet의 노드 상태 업데이트 실패
"나는 보고하려고 했어! apiserver가 안 받아줬을 뿐이야."
마지막으로 노드 에이전트인 kubelet의 로그를 확인했다. kubelet은 열심히 자신의 생존 신호(Heartbeat)를 보내려 시도했다.
주요 로그 패턴
1. Node Lease 갱신 실패
Nov 10 16:30:45 kubelet: failed to update node lease, error: Put ... context deadline exceeded
Nov 10 16:30:57 kubelet: ... use of closed network connection
- kubelet이 kube-apiserver의 endpoint인
https://localhost:6443로 Lease 갱신 요청을 보냈지만 4초 타임아웃 혹은 연결 종료로 실패했다. (단일 마스터인 환경이기에 kube-apiserver의 주소가 localhost로 되어있는 상태)
2. Node Status 갱신 실패
Nov 10 16:30:58 kubelet: Error updating node status ... http2: client connection force closed via ClientConn.Close
- 상태 업데이트 역시 apiserver와의 HTTP2 연결이 강제로 끊기며 실패했다.
결과: 노드 NotReady 판정
컨트롤 플레인의 Node Lifecycle Controller 입장에서는 다음과 같이 보였을 것이다.
- Lease 갱신이 안 들어옴: etcd 지연 → apiserver 먹통 → kubelet 요청 실패.
- Grace Period 초과: 설정된 시간(기본 40초) 동안 하트비트가 없자 노드를 Unknown/NotReady로 마킹.
- 장애 확정: 운영자에게는 "노드가 죽었다"는 알람이 발송됨.
정리
이번 장애의 핵심은 "노드 상태가 이상하다고 해서 반드시 노드의 문제는 아니다" 라는 점이다.
- 원인: etcd가 사용하는 스토리지/디스크의 I/O Latency 급증
- 과정: etcd 지연 → apiserver gRPC 통신 두절 → kubelet의 Lease/Status 갱신 요청 실패
- 결과: 컨트롤 플레인에 의한 노드 NotReady 판정
etcd 로그에서 sync duration이나 took too long 메시지가 빈번하다면, 즉시 디스크 성능(IOPS, Latency)을 점검하고 etcd 전용 고성능 디스크 분리를 고려해야 한다.
중요
잘못된 정보나, 문의등은 댓글로 메일과 함께 적어주시면 감사하겠습니다.
'Kubernetes' 카테고리의 다른 글
| GET 그리고 WATCH는 뭐가 다를까? - OpenTelemetry 장애 케이스 (0) | 2026.01.08 |
|---|---|
| Disk Thin Provisioning 방식과 Node Deadlock 상관관계 (1) | 2026.01.01 |
| Ingress NGINX의 공식 은퇴 (0) | 2025.11.27 |
| Kubernetes Node Life Cycle - 노드의 생명주기 (0) | 2025.11.26 |
| Kubernetes Calico CNI와 스케줄링 실패 관계 (0) | 2025.11.06 |