Files
obsidian/history/2026-06-11-kr2-k3s-readonly-hang.md

4.4 KiB

date, topic, areas, tags
date topic areas tags
2026-06-11 kr2 K3s control-plane 8h hang — Patroni failover 후 read-only DB로 kine 기동 wedge
infra/compute/hosts/incus-kr2.md
infra/data/postgresql-ha.md
history
incident
k3s
patroni
kine
postgresql

K3s 점검 중 발견. incus-kr2 control-plane의 k3s.service가 2026-06-10 22:55부터 약 8시간 activating 상태로 멈춰 kr3 컨텍스트 API(100.119.109.41:6443) connection refused.

원인 체인

  1. 2026-06-10 22:55경 Patroni failover 발생 (leader → postgres-2 / 10.100.3.185, incus-kr1). 전환 윈도우 동안 3개 Postgres 노드가 모두 read-only.
  2. 마침 그 시점에 kr2 k3s가 (재)기동 중이었고, kine(pgx)이 설정된 노드 IP 3개(10.100.2.5 / 10.100.3.185 / 10.100.1.83)에 직접 연결 시도 → 전부 ValidateConnect failed: read only connection.
  3. k3s가 Configuring pgx database connection pooling 로그 직후 프로세스 hang (PID 3580986, STAT=Ssl). 8시간 동안 추가 로그 0, SIGTERM 무시(systemd deactivating에서 대기).
  4. Patroni는 이후 정상 회복(leader 선출 완료)됐지만 kr2 k3s는 자가복구 못 하고 wedge 유지.

영향

  • 클러스터는 kr1 control-plane으로 계속 서빙(/healthz ok)되어 외부 영향 제한적. kr2만 API/스케줄 제외.
  • 동반: apisix/apisix-etcd-1(kr1) 같은 22:55 이벤트로 etcd raft commitTo panic → CrashLoopBackOff. etcd quorum 2/3(hp1/hp2) 유지로 APISIX는 동작. → 씬(syn) 도메인, 별도 remediation 필요.

복구

ssh kaffa@100.119.109.41           # incus-kr2
sudo kill -9 3580986               # hang된 k3s PID 강제 종료 (SIGTERM 무시함)
sudo systemctl start k3s           # 재기동 → 정상 leader(postgres-2)에 연결, 합류
  • 복구 후 4노드 전부 Ready (kr1/kr2 control-plane, hp1/hp2 worker, v1.34.7+k3s1).

확정 근본 원인 (2026-06-11 정밀 분석)

  1. 22:55:08 Patroni가 잠깐 all-read-only (DCS/etcd-nas 순간 블립으로 failsafe 추정. 현재 etcd-nas DCS·Patroni 모두 정상). postgres-2 patroni 로그에 명시적 failover 라인은 없음 → 클린 failover가 아니라 일시적 전원 read-only 윈도우.
  2. 실행 중이던 kr2 k3s가 read-only로 leader-election lease 갱신 실패leaderelection lost → controller-manager 종료 → k3s.service exit code=1.
  3. systemd가 재시작(Restart=always) → 아직 read-only 윈도우 → kine 기동이 Configuring pgx pool에서 hang.
  4. k3s.service Type=notify + TimeoutStartSec=0(무한) 이라, 기동 중 READY 전송 전 hang하면 systemd가 영원히 대기(activating 8h). Restart=always는 프로세스가 안 죽으니 무용.

적용한 조치 (2026-06-11)

  1. k3s hang 자동복구 (핵심 재발방지): kr1·kr2에 systemd drop-in /etc/systemd/system/k3s.service.d/timeout-override.confTimeoutStartSec=300. → 기동 hang 시 5분 후 systemd가 kill, Restart=always로 재시도. DB가 RW 될 때까지 5분 주기 self-heal. (8h 행 → 최대 ~5분)
    • datastore-endpoint는 변경하지 않음 (아래 주의 참조).
  2. 즉시 복구: hang PID SIGKILL + systemctl start k3s → 4노드 Ready.
  3. 동반 손상 apisix-etcd-1(kr1) 멤버: etcdctl member remove + 데이터 wipe + 파드 재기동으로 fresh 재합류(새 id d2504d737a8e493f). etcd 3/3 healthy 복구.

⚠️ 주의 — datastore를 HAProxy로 바꾸지 말 것

당초 2026-04-08-patroni-failover-incident 교훈("HAProxy 경유")을 떠올렸으나, ../infra/data/postgresql-ha 기준 HAProxy(192.168.9.1:5432)는 2026-04-16 폐기되었고 현재 K3s kine은 pgx multi-host(target_session_attrs=read-write) 3노드 직결이 정식 구성이다(앱은 pgpool-II 경유). HAProxy는 현재 죽어있는 게 정상. → datastore-endpoint 변경은 정식 결정을 되돌리는 것이므로 금지. 문제는 endpoint가 아니라 k3s 기동 hang 자가복구 부재였고, 그것을 TimeoutStartSec로 해결함.

재발 패턴

참조