LabHub
배우기 러닝패스 코스

Kubernetes運用実務

ノードを空けてアップグレード計画を立てる

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

노드 한 대를 안전하게 비우고 되돌리는 절차를 손으로 수행하고, 버전 스큐 규칙과 카나리 롤아웃 계획을 문서가 아니라 검증 가능한 산출물로 만듭니다.

왜 중요한가

업그레이드 사고의 대부분은 명령을 몰라서가 아니라 순서와 범위를 몰라서 납니다. 되돌릴 수 없는 작업(kubeadm upgrade apply) 앞에는 반드시 etcd 스냅샷이 와야 합니다. 컨트롤 플레인 다운그레이드는 지원되지 않으므로, 잘못됐을 때의 탈출구는 "내리기"가 아니라 "스냅샷으로 복구하기"뿐이기 때문입니다. 범위 문제는 버전 스큐가 담당합니다. kubelet 은 apiserver 보다 낮을 수는 있어도 높을 수 없고, kubectl 만 유일하게 위로 한 칸을 허용합니다. 이 비대칭을 모르면 "kubectl 은 최신으로 써도 되는데 왜 kubelet 은 안 되지" 같은 질문에서 막힙니다. 마지막으로 노드 작업의 3단계(cordon → drain → uncordon)와 PDB 는 짝입니다. PDB 가 없으면 drain 이 서비스를 통째로 내릴 수 있고, PDB 가 지나치게 빡빡하면 drain 이 영원히 끝나지 않습니다.

단계

  1. /root/ops/upgrade/out/versions.json 을 만드세요. 최상위 키는 server(v1.x.y 형식의 서버 버전 문자열)와 nodes 입니다. nodeslab-node-0, lab-node-1, lab-node-2 세 개를 키로 갖고 값은 각 노드의 실제 kubelet 버전 문자열이어야 합니다.
  2. lab-node-1 만 cordon 하고, 직후의 노드 목록을 /root/ops/upgrade/out/cordon.txt 에 저장하세요. 파일에 lab-node-1SchedulingDisabled 가 보여야 하며 lab-node-0 은 차단되면 안 됩니다. 그리고 /root/ops/upgrade/out/cordon-note.txt 에 cordon 이 이미 떠 있는 파드는 건드리지 않는다는 점을 한 줄로 적으세요.
  3. 네임스페이스 ops-upgrade 를 만들고 그 안에 replicas: 3 인 Deployment web(파드 라벨 app=web)을 만드세요. 이어서 PodDisruptionBudget web-pdb 를 같은 네임스페이스에 만들되 spec.minAvailable: 2, spec.selector.matchLabels.app: web 으로 하고 maxUnavailable쓰지 마세요.
  4. lab-node-1 을 drain 하고 그 출력을 /root/ops/upgrade/out/drain.txt 에 저장하세요. drain 이 끝난 뒤 ops-upgrade 네임스페이스 파드가 어느 노드에 있는지를 /root/ops/upgrade/out/after-drain.txt 에 세 줄 이상으로 남기세요. 이 파일에 lab-node-1 이 들어 있으면 안 되고 lab-node-0 또는 lab-node-2 가 보여야 합니다.
  5. lab-node-1 을 uncordon 하고 그 출력을 /root/ops/upgrade/out/uncordon.txt 에 저장하세요. 세 노드 모두 스케줄 가능 상태여야 하며 Deployment web 의 준비된 복제본이 다시 3개가 되어야 합니다.
  6. /opt/lab/fixtures/k8s/skew-template.yaml/root/ops/upgrade/skew.yaml 로 복사한 뒤 answers 아래 물음표를 채우세요. apiserver: "1.34" 는 문제의 전제이므로 그대로 둡니다. 정답 형식은 "1.31" 처럼 마이너 버전 문자열이며, downgrade_supported"yes" 또는 "no" 입니다. 채워야 할 키는 min_kubelet, max_kubelet, max_kubectl, min_kubectl, max_controller_manager, next_upgrade_target, downgrade_supported 입니다.
  7. /root/ops/upgrade/runbook.md 를 500바이트 이상으로 쓰세요. 각 항목은 서로 다른 줄에 두고 다음 순서를 지켜야 합니다. (1) etcd 스냅샷 백업, (2) kubeadm upgrade plan, (3) 첫 컨트롤 플레인에서 kubeadm upgrade apply, (4) 나머지 노드에서 kubeadm upgrade node, 그리고 노드 작업 구간에서 drainuncordon 보다 먼저 나와야 합니다. 마이너 버전을 건너뛸 수 없다는 제약도 문장으로 적으세요(예: "한 번에 하나").
  8. 세 노드에 upgrade.labhub.io/stage 라벨을 붙이세요. lab-node-0canary, lab-node-1batch1, lab-node-2batch2 입니다. 그리고 /root/ops/upgrade/out/rollout.json 에 계획을 쓰세요. stages 는 길이 3의 배열이고 각 원소는 stage(canary/batch1/batch2)와 nodes(노드 이름 배열)를 갖습니다. 첫 단계는 canary 이며 노드가 정확히 1대여야 하고, 세 노드가 모두 어딘가에 배정돼야 합니다. 최상위에 verify_between_stages 키를 두고 단계 사이에 무엇을 확인할지 적으세요.

참고

컨트롤 플레인과 노드 버전 수집하기

/root/ops/upgrade/out/versions.json 을 만드세요. 최상위 키는 server(v1.x.y 형식의 서버 버전 문자열)와 nodes 입니다. nodeslab-node-0, lab-node-1, lab-node-2 세 개를 키로 갖고 값은 각 노드의 실제 kubelet 버전 문자열이어야 합니다.

업그레이드는 현재 버전을 정확히 아는 데서 시작합니다. 서버 버전과 각 노드의 kubelet 버전은 서로 다른 곳에서 읽습니다. 노드 정보는 status.nodeInfo 아래에 있습니다.

노드 한 대만 스케줄 차단하기

lab-node-1 만 cordon 하고, 직후의 노드 목록을 /root/ops/upgrade/out/cordon.txt 에 저장하세요. 파일에 lab-node-1SchedulingDisabled 가 보여야 하며 lab-node-0 은 차단되면 안 됩니다. 그리고 /root/ops/upgrade/out/cordon-note.txt 에 cordon 이 이미 떠 있는 파드는 건드리지 않는다는 점을 한 줄로 적으세요.

한 번에 한 대씩이 원칙입니다. cordon 은 앞으로의 스케줄만 막고 이미 떠 있는 파드는 건드리지 않는다는 점을 메모로 남기세요.

가용성을 지킬 PDB 만들기

네임스페이스 ops-upgrade 를 만들고 그 안에 replicas: 3 인 Deployment web(파드 라벨 app=web)을 만드세요. 이어서 PodDisruptionBudget web-pdb 를 같은 네임스페이스에 만들되 spec.minAvailable: 2, spec.selector.matchLabels.app: web 으로 하고 maxUnavailable쓰지 마세요.

복제본 3개 중 최소 몇 개가 살아 있어야 하는지를 선언합니다. 최소값과 최대 불가용값은 함께 쓸 수 없습니다.

노드 비우고 파드 이동 확인하기

lab-node-1 을 drain 하고 그 출력을 /root/ops/upgrade/out/drain.txt 에 저장하세요. drain 이 끝난 뒤 ops-upgrade 네임스페이스 파드가 어느 노드에 있는지를 /root/ops/upgrade/out/after-drain.txt 에 세 줄 이상으로 남기세요. 이 파일에 lab-node-1 이 들어 있으면 안 되고 lab-node-0 또는 lab-node-2 가 보여야 합니다.

drain 은 cordon 에 더해 기존 파드를 쫓아냅니다. 데몬셋과 emptyDir 관련 옵션이 없으면 거부당합니다. 비운 뒤 파드가 어느 노드에 있는지 저장하세요.

작업 끝난 노드 되돌리기

lab-node-1 을 uncordon 하고 그 출력을 /root/ops/upgrade/out/uncordon.txt 에 저장하세요. 세 노드 모두 스케줄 가능 상태여야 하며 Deployment web 의 준비된 복제본이 다시 3개가 되어야 합니다.

uncordon 을 잊으면 그 노드는 조용히 놀게 됩니다. 세 노드 모두 스케줄 가능 상태여야 하고 워크로드도 원래 개수로 돌아와야 합니다.

버전 스큐 표 채우기

/opt/lab/fixtures/k8s/skew-template.yaml/root/ops/upgrade/skew.yaml 로 복사한 뒤 answers 아래 물음표를 채우세요. apiserver: "1.34" 는 문제의 전제이므로 그대로 둡니다. 정답 형식은 "1.31" 처럼 마이너 버전 문자열이며, downgrade_supported"yes" 또는 "no" 입니다. 채워야 할 키는 min_kubelet, max_kubelet, max_kubectl, min_kubectl, max_controller_manager, next_upgrade_target, downgrade_supported 입니다.

기준은 언제나 apiserver 입니다. kubelet 은 아래로 3마이너, 컨트롤러는 아래로 1마이너, kubectl 만 위아래 1마이너입니다. 마이너는 한 번에 하나씩 올립니다.

업그레이드 런북 쓰기

/root/ops/upgrade/runbook.md 를 500바이트 이상으로 쓰세요. 각 항목은 서로 다른 줄에 두고 다음 순서를 지켜야 합니다. (1) etcd 스냅샷 백업, (2) kubeadm upgrade plan, (3) 첫 컨트롤 플레인에서 kubeadm upgrade apply, (4) 나머지 노드에서 kubeadm upgrade node, 그리고 노드 작업 구간에서 drainuncordon 보다 먼저 나와야 합니다. 마이너 버전을 건너뛸 수 없다는 제약도 문장으로 적으세요(예: "한 번에 하나").

되돌릴 수 없는 작업 앞에는 백업이 옵니다. 첫 컨트롤 플레인과 나머지 노드가 쓰는 kubeadm 하위 명령이 다르다는 점도 적으세요.

카나리 롤아웃 계획 세우고 라벨 붙이기

세 노드에 upgrade.labhub.io/stage 라벨을 붙이세요. lab-node-0canary, lab-node-1batch1, lab-node-2batch2 입니다. 그리고 /root/ops/upgrade/out/rollout.json 에 계획을 쓰세요. stages 는 길이 3의 배열이고 각 원소는 stage(canary/batch1/batch2)와 nodes(노드 이름 배열)를 갖습니다. 첫 단계는 canary 이며 노드가 정확히 1대여야 하고, 세 노드가 모두 어딘가에 배정돼야 합니다. 최상위에 verify_between_stages 키를 두고 단계 사이에 무엇을 확인할지 적으세요.

계획을 문서로만 두지 말고 노드 라벨로 클러스터에 새기세요. 첫 단계는 한 대여야 하고, 단계 사이에 무엇을 확인할지가 카나리의 핵심입니다.