IL-0113 Webhook Relay · 2022-05-10kubernetesgcp
Webhook Relay 는 2017년부터 GKE 를 써 왔고, 컨트롤러와 백엔드 API 가 있는 메인 리전을 GKE 클러스터에서 운영했다. 2022년 5월 10일 이 클러스터의 관리형 컨트롤 플레인이 망가져 큰 장애가 났다. 팀은 12시 40분에 원인이 쿠버네티스 API 서버 인증서임을 알아냈다. 예전에 만든 GKE 클러스터는 5년짜리 인증서를 받았고 지금 만드는 클러스터는 30년짜리를 받는데, 이 클러스터에서는 인증서 교체가 한 번도 일어나지 않았다.
팀은 수동 인증서 교체를 시작했다. 교체 과정에서 노드가 다시 만들어져야 했지만 아무 일도 일어나지 않아 노드 풀을 손으로 다시 만들었다. 교체 작업은 성공했다고 나왔지만 실제로는 효과가 없었고, 컨트롤 플레인 업그레이드도 도움이 되지 않았다. 파드는 돌았지만 서비스 어카운트 인증이 실패해 뒤에 있는 서비스에 닿지 못했다.
인증 오류를 확인한 뒤 팀은 서비스를 새 클러스터로 옮기기 시작했다. 로드 밸런서와 PVC 가 기존 클러스터에 묶여 있어서 먼저 떼어 내야 했다. 16시 50분 기존 클러스터에서 쿠버네티스 Service 레코드를 지운 뒤에야 새 클러스터에 붙일 수 있었다. 17시 10분 새 백엔드가 떴지만 웹훅 라우트가 새 디스크에 쓰고 있었다. 17시 30분 StatefulSet 도 떼어 내 모든 쓰기를 메인 디스크로 돌렸고, 18시 30분 임시 ClickHouse 인스턴스의 데이터를 내보내 메인 인스턴스에 다시 넣었다.
장애 내내 기존 클러스터가 곧 살아날 것처럼 보였기 때문에 복구가 길어졌다. 팀은 관리형 클러스터가 완전히 망가졌다는 것을 알았다면 처음부터 새 클러스터로 옮겼을 것이고, 디스크를 옮기고 로드 밸런서를 떼어 내는 수고를 감안해도 훨씬 빨랐을 것이라고 적었다. 여러 가용 영역에 걸친 GKE 구성은 이번 장애에서 도움이 되지 않았다.
2022년 5월 10일 낮 12시 EST 에 헬스체크 시스템이 경보를 울렸다. EU 리전의 백엔드 API, 프런트엔드, 터널이 모두 내려가 있었다. 처음에는 클라이언트 쪽에서 요청이 끊겼거나, 메모리나 CPU 사용량 때문에 축출된 서버에 요청이 닿은 일시적 오류라고 생각했다. 메인 대시보드가 내려간 것을 보고 바로 대응을 시작했다.
12시 10분에는 쿠버네티스 클러스터의 정보가 서로 맞지 않았다. 노드가 죽었거나 업그레이드 중인 것처럼 보였다. 몇 년 전 GKE 자동 유지보수 업그레이드가 잘못됐을 때와 비슷했지만 유지보수 시간대가 아니었다. 12시 20분에는 노드 풀 재생성이 오래 걸렸고, 클러스터 요청이 타임아웃 났고, 작업이 여러 번 실패한 뒤에야 성공했다.
GKE 콘솔은 완전히 정상도 아니고 확실히 망가진 것도 아닌 상태로 보였다. 콘솔에서 노드 풀을 보고 만들고 관리할 수 있었고, 노드는 정상 상태가 되어 워크로드를 띄웠지만 모든 작업이 매우 느렸다. 디플로이먼트를 고치고 로그를 보는 것도, 컨트롤 플레인 버전을 올리는 것도 됐다. 반면 kubectl 은 오브젝트를 조회할 수는 있었지만 로그를 보거나 포트 포워딩을 할 수 없었고 오브젝트를 수정할 수 없었다. 일부 워크로드 정보는 분명히 오래된 값으로 나왔다.
13시 50분 워크로드가 다시 떴지만 클러스터 안의 서비스 어카운트 기반 인증이 실패했다. 백엔드 서비스가 Cloud SQL, PubSub, GCS 에 연결하지 못했다. 14시 30분 무렵 서비스를 복제하고 있던 새 클러스터도 몇 분마다 컨트롤 플레인이 응답하지 않았다. 15시에는 포트 포워딩 명령이 실패해 웹훅 로그를 저장하는 ClickHouse 데이터베이스에 접속할 수 없었고, 쿠버네티스 API 로도 로그를 볼 수 없었다.
원인 ? 인증서·자격 증명 만료
헬스체크 시스템이 서비스가 내려갔다는 첫 알림을 보냈다. 팀은 처음에 일시적 오류로 보고 자동 복구를 기대했지만, 메인 대시보드가 내려간 것을 확인하고 바로 대응을 시작했다.
기존 인프라를 살리는 작업에는 시간 상한을 정해야 한다. 장애 내내 서비스가 곧 살아날 것처럼 보였지만, 기존 클러스터를 훨씬 일찍 포기하고 새 클러스터에서 다시 시작했어야 했다. 이미 들인 노력이 아까워 살리기를 멈추지 못한 것이 판단을 늦췄다.
오래된 GKE 클러스터라면 클러스터 CA 인증서의 유효기간을 `gcloud container clusters describe <cluster name> --zone europe-north1-a --format "value(masterAuth.clusterCaCertificate)" | base64 --decode | openssl x509 -text | grep Validity -A 2` 로 확인할 수 있다.
같은 원인 · 공통 노드 풀
같은 원인 · 공통 쿠버네티스 API 서버
같은 원인 · 공통 쿠버네티스 API 서버