{"id":"IL-0185","org":"Hans H. Kim","date":"2023-05-07","docs":["https://kubespray.io/#/docs/nodes"],"title":{"en":"A disk failure made the first control plane node of a Kubespray cluster read-only, and recovery needed the Kubespray inventory reordered and a new control plane node joined","ko":"Kubespray 로 만든 클러스터의 첫 번째 control plane 노드 디스크가 I/O 오류로 읽기 전용이 되면서 노드가 죽었다"},"domain":["kubernetes"],"impact":{"scope":"the first control plane (master) node of a three-node control plane","users":"unknown","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"In a Kubespray cluster the first node of the kube_control_plane inventory group is special, so its failure needs its own procedure: move another node into the first position, fix the cluster-info ConfigMap, join a new control plane node and add the etcd member back. etcd should be brought back to full membership before another control plane node fails.","ko":"Kubespray 는 첫 번째 control plane 노드에 특별한 권한을 주기 때문에, master 세 대로 HA 를 구성해도 1번 노드의 장애 복구는 매우 까다롭다. 복구하려면 inventory 순서를 바꿔 1번 역할부터 다른 노드로 넘겨야 한다. control plane 노드가 죽으면 etcd 쿼럼이 위험해지므로 다른 노드가 더 망가지기 전에 etcd 를 되살려야 한다."},"related":[],"sources":[{"url":"https://hhhyunwoo.github.io/posts/k8s-kubespray-master1/","kind":"blog","license":"cc-by","archived":null}],"summary":{"en":"The cluster was built with Kubespray and had three master nodes. A hardware failure took down the first control plane node. Because Kubespray treats the first node in the kube_control_plane group specially, recovering that node is very tricky.\n\nThe recovery went in steps. The control plane order in the Kubespray inventory was changed from node-1, node-2, node-3 to node-2, node-3, node-1 so that another node took the first position, and the failed machine was removed from the cluster. The cluster-info ConfigMap in kube-public was edited with kubectl edit cm -n kube-public cluster-info to replace the old control plane IP with a live node's IP and to change certificate-authority-data. A new control plane node was then prepared by hand: swap turned off, systemd-resolved started, Docker, conntrack, kubeadm and kubelet installed, the certificates in /etc/kubernetes/ssl and /etc/ssl/etcd/ssl copied over, and the CNI plugins v0.9.1 installed. It joined with kubeadm join ... --control-plane --v=5 --skip-phases control-plane-join/etcd, and the etcd member was added separately.\n\nThe author warns that losing one or more of the three control plane machines breaks the etcd quorum, so etcd has to be recovered before another node fails.","ko":"이 클러스터는 Kubespray 로 구성했고, master 노드 세 대로 HA 를 이루고 있었다. 하드웨어 장애로 첫 번째 control plane 노드인 master 1번이 죽었다. Kubespray 는 master 1번 노드에 특별한 권한을 주기 때문에, 이 노드를 복구하는 일은 매우 까다롭다.\n\n복구는 Kubespray inventory 의 [kube_control_plane] 순서를 node-1, node-2, node-3 에서 node-2, node-3, node-1 로 바꿔 1번 역할을 다른 노드에 넘기는 데서 시작했다. 그다음 장애 난 장비를 클러스터에서 제거했다. kube-public 네임스페이스의 cluster-info ConfigMap 에서는 옛 control plane 장비의 IP 를 살아 있는 장비의 IP 로 바꾸고 certificate-authority-data 값도 바꿨다.\n\n새 노드에서는 swap 을 끄고 systemd-resolved 를 실행한 뒤 docker, conntrack, kubeadm, kubelet 을 설치했다. 이어서 인증서를 복사하고 CNI 플러그인 v0.9.1 을 설치했다. 그런 다음 kubeadm join 에 --control-plane 과 --skip-phases control-plane-join/etcd 옵션을 주어 새 노드를 control plane 에 합류시켰고, 마지막으로 etcd 노드를 추가했다.\n\n글쓴이는 control plane 세 대 가운데 한 대 이상이 죽으면 Kubernetes 에서 가장 중요한 etcd 의 쿼럼이 깨지므로, 다른 노드가 더 망가지기 전에 etcd 를 복구해야 한다고 적었다."},"trigger":{"en":"A hardware failure of the disk on the first control plane node.","ko":"하드웨어 장애로 master 1번 노드의 sda 디스크에 I/O 오류가 나고 읽기 전용 상태가 됐다."},"severity":"unknown","symptoms":["node-not-ready"],"timeline":{"detected_after":null,"resolved_after":null},"date_kind":"published","detection":{"en":"Disk I/O errors from blk_update_request on dev sda appeared in the node's kernel log.","ko":"커널 로그에 sda 디스크의 blk_update_request I/O 오류가 찍히면서 디스크 장애를 알았다."},"components":["kubespray","etcd","node-disk","configmap"],"root_cause":"hardware-failure","remediation":[{"text":{"en":"reordered the kube_control_plane group in the Kubespray inventory so that node-2 became the first control plane node","ko":"Kubespray inventory 의 kube_control_plane 순서를 바꿔 node-2 가 첫 번째 control plane 노드가 되게 했다."}},{"text":{"en":"removed the failed machine from the cluster","ko":"하드웨어 장애가 난 1번 장비를 클러스터에서 제거했다."}},{"text":{"en":"edited the cluster-info ConfigMap in kube-public to point at a live control plane node and updated certificate-authority-data","ko":"kubectl edit cm -n kube-public cluster-info 로 cluster-info ConfigMap 의 옛 control plane IP 를 살아 있는 장비의 IP 로 바꾸고 certificate-authority-data 값도 바꿨다."}},{"text":{"en":"installed and configured kubelet and the other components on a new node and joined it as a control plane node with kubeadm, skipping the etcd join phase","ko":"새 노드에 kubelet 을 비롯한 컴포넌트를 설치하고 kubeadm join --control-plane --skip-phases control-plane-join/etcd 로 control plane 노드를 추가했다."}},{"text":{"en":"added the etcd member separately","ko":"etcd 노드를 따로 추가했다."}}],"action_items":[],"contributing":["single-point-of-failure"],"recurrence_of":null,"symptoms_text":{"en":"The kernel on a master node of the Kubernetes cluster logged disk I/O errors: \"[HAWKEYE] kernel:: [22329228.540857] blk_update_request: I/O error, dev sda, sector 795030104 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0\". The sda disk switched to read-only, and the machine needed a new disk and an operating system reinstall.\n\nThe control plane ran on three master nodes for high availability, but the failed machine was the first control plane node, which Kubespray gives special privileges, so recovering it was much harder than recovering one of the other two.","ko":"Kubernetes 클러스터의 master 노드에서 디스크 장애가 났다. 커널 로그에 \"[HAWKEYE] kernel:: [22329228.540857] blk_update_request: I/O error, dev sda, sector 795030104 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 0, at\" 오류가 찍혔다.\n\n디스크 장애로 sda 영역이 읽기 전용 상태로 바뀌었고, 디스크 교체와 OS 재설치가 필요해졌다. 장애 난 노드는 세 대로 HA 를 구성한 master 가운데 1번 노드였다."},"updated_at":"2026-11-09T11:55:57.381826Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0185","org_slug":"hans-h-kim"}