Draining Nodes and Planning the Upgrade
한국어 원문으로 표시합니다.
목표
노드 한 대를 안전하게 비우고 되돌리는 절차를 손으로 수행하고, 버전 스큐 규칙과 카나리 롤아웃 계획을 문서가 아니라 검증 가능한 산출물로 만듭니다.
왜 중요한가
업그레이드 사고의 대부분은 명령을 몰라서가 아니라 순서와 범위를 몰라서 납니다. 되돌릴 수 없는 작업(kubeadm upgrade apply) 앞에는 반드시 etcd 스냅샷이 와야 합니다. 컨트롤 플레인 다운그레이드는 지원되지 않으므로, 잘못됐을 때의 탈출구는 "내리기"가 아니라 "스냅샷으로 복구하기"뿐이기 때문입니다. 범위 문제는 버전 스큐가 담당합니다. kubelet 은 apiserver 보다 낮을 수는 있어도 높을 수 없고, kubectl 만 유일하게 위로 한 칸을 허용합니다. 이 비대칭을 모르면 "kubectl 은 최신으로 써도 되는데 왜 kubelet 은 안 되지" 같은 질문에서 막힙니다. 마지막으로 노드 작업의 3단계(cordon → drain → uncordon)와 PDB 는 짝입니다. PDB 가 없으면 drain 이 서비스를 통째로 내릴 수 있고, PDB 가 지나치게 빡빡하면 drain 이 영원히 끝나지 않습니다.
단계
/root/ops/upgrade/out/versions.json을 만드세요. 최상위 키는server(v1.x.y형식의 서버 버전 문자열)와nodes입니다.nodes는lab-node-0,lab-node-1,lab-node-2세 개를 키로 갖고 값은 각 노드의 실제 kubelet 버전 문자열이어야 합니다.lab-node-1만 cordon 하고, 직후의 노드 목록을/root/ops/upgrade/out/cordon.txt에 저장하세요. 파일에lab-node-1과SchedulingDisabled가 보여야 하며lab-node-0은 차단되면 안 됩니다. 그리고/root/ops/upgrade/out/cordon-note.txt에 cordon 이 이미 떠 있는 파드는 건드리지 않는다는 점을 한 줄로 적으세요.- 네임스페이스
ops-upgrade를 만들고 그 안에replicas: 3인 Deploymentweb(파드 라벨app=web)을 만드세요. 이어서 PodDisruptionBudgetweb-pdb를 같은 네임스페이스에 만들되spec.minAvailable: 2,spec.selector.matchLabels.app: web으로 하고maxUnavailable은 쓰지 마세요. 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가 보여야 합니다.lab-node-1을 uncordon 하고 그 출력을/root/ops/upgrade/out/uncordon.txt에 저장하세요. 세 노드 모두 스케줄 가능 상태여야 하며 Deploymentweb의 준비된 복제본이 다시 3개가 되어야 합니다./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입니다./root/ops/upgrade/runbook.md를 500바이트 이상으로 쓰세요. 각 항목은 서로 다른 줄에 두고 다음 순서를 지켜야 합니다. (1) etcd 스냅샷 백업, (2)kubeadm upgrade plan, (3) 첫 컨트롤 플레인에서kubeadm upgrade apply, (4) 나머지 노드에서kubeadm upgrade node, 그리고 노드 작업 구간에서drain이uncordon보다 먼저 나와야 합니다. 마이너 버전을 건너뛸 수 없다는 제약도 문장으로 적으세요(예: "한 번에 하나").- 세 노드에
upgrade.labhub.io/stage라벨을 붙이세요.lab-node-0은canary,lab-node-1은batch1,lab-node-2는batch2입니다. 그리고/root/ops/upgrade/out/rollout.json에 계획을 쓰세요.stages는 길이 3의 배열이고 각 원소는stage(canary/batch1/batch2)와nodes(노드 이름 배열)를 갖습니다. 첫 단계는canary이며 노드가 정확히 1대여야 하고, 세 노드가 모두 어딘가에 배정돼야 합니다. 최상위에verify_between_stages키를 두고 단계 사이에 무엇을 확인할지 적으세요.
참고
- 서버 버전은
kubectl version -o json의.serverVersion.gitVersion, 노드의 kubelet 버전은kubectl get nodes -o json의.items[].status.nodeInfo.kubeletVersion에 있습니다.jq의from_entries를 쓰면 이름을 키로 하는 객체를 쉽게 만들 수 있습니다. - drain 은 데몬셋 파드나 emptyDir 를 쓰는 파드가 있으면 그냥은 거부합니다.
--ignore-daemonsets,--delete-emptydir-data, 필요하면--force를 붙이세요. - 파드가 어느 노드에 있는지는
kubectl get pods -n ops-upgrade -o wide --no-headers로 한 줄에 하나씩 볼 수 있습니다. - 라벨에 점과 슬래시가 들어가면 jsonpath 에서 이스케이프가 필요합니다. 확인은
kubectl get nodes -L upgrade.labhub.io/stage가 가장 간편합니다. - 흔한 실수 1: 7번 런북에서
kubeadm upgrade apply와kubeadm upgrade node를 한 줄에 같이 쓰는 것. 두 명령의 첫 등장 줄 번호로 순서를 판정하므로 같은 줄이면 통과하지 못합니다.drain과uncordon도 마찬가지입니다. - 흔한 실수 2: 6번에서 kubectl 의 상한을 apiserver 와 같은 값으로 적는 것. kubectl 은 유일하게 위로 한 칸을 허용합니다.
- 실습 파드는 실습마다 새로 뜨므로 앞 실습의 클러스터 상태는 남아 있지 않습니다.
ops-upgrade네임스페이스와 Deployment 는 3번에서 직접 만드세요. 운영 절차를 기억이 아니라 런북과 매니페스트로 남겨야 하는 이유가 바로 이것입니다.
컨트롤 플레인과 노드 버전 수집하기
/root/ops/upgrade/out/versions.json 을 만드세요. 최상위 키는 server(v1.x.y 형식의 서버 버전 문자열)와 nodes 입니다. nodes 는 lab-node-0, lab-node-1, lab-node-2 세 개를 키로 갖고 값은 각 노드의 실제 kubelet 버전 문자열이어야 합니다.
업그레이드는 현재 버전을 정확히 아는 데서 시작합니다. 서버 버전과 각 노드의 kubelet 버전은 서로 다른 곳에서 읽습니다. 노드 정보는 status.nodeInfo 아래에 있습니다.
노드 한 대만 스케줄 차단하기
lab-node-1 만 cordon 하고, 직후의 노드 목록을 /root/ops/upgrade/out/cordon.txt 에 저장하세요. 파일에 lab-node-1 과 SchedulingDisabled 가 보여야 하며 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, 그리고 노드 작업 구간에서 drain 이 uncordon 보다 먼저 나와야 합니다. 마이너 버전을 건너뛸 수 없다는 제약도 문장으로 적으세요(예: "한 번에 하나").
되돌릴 수 없는 작업 앞에는 백업이 옵니다. 첫 컨트롤 플레인과 나머지 노드가 쓰는 kubeadm 하위 명령이 다르다는 점도 적으세요.
카나리 롤아웃 계획 세우고 라벨 붙이기
세 노드에 upgrade.labhub.io/stage 라벨을 붙이세요. lab-node-0 은 canary, lab-node-1 은 batch1, lab-node-2 는 batch2 입니다. 그리고 /root/ops/upgrade/out/rollout.json 에 계획을 쓰세요. stages 는 길이 3의 배열이고 각 원소는 stage(canary/batch1/batch2)와 nodes(노드 이름 배열)를 갖습니다. 첫 단계는 canary 이며 노드가 정확히 1대여야 하고, 세 노드가 모두 어딘가에 배정돼야 합니다. 최상위에 verify_between_stages 키를 두고 단계 사이에 무엇을 확인할지 적으세요.
계획을 문서로만 두지 말고 노드 라벨로 클러스터에 새기세요. 첫 단계는 한 대여야 하고, 단계 사이에 무엇을 확인할지가 카나리의 핵심입니다.