영어로 배우는 Cluster API: KubeVirt 위에 클러스터 찍어 내기
Day 2: scale, replace, remediate, roll out
목표
워크로드 클러스터의 워커를 늘리고 줄이고, Machine 을 지워 되살아나는 것을 보고, MachineHealthCheck 로 죽은 노드가 자동 교체되게 만듭니다. 워커 템플릿을 새로 만들어 롤링 교체한 뒤, 그 변경을 영어 PR 설명과 리뷰 답글로 씁니다.
왜 중요한가
클러스터를 한 번 세우는 것보다 그다음이 깁니다. Cluster API 는 노드를 "고칠 대상" 이 아니라 "바꿀 대상" 으로 봅니다. 그래서 스케일, 교체, 자동 복구, 판 올리기가 모두 '새 Machine 을 만들고 옛 Machine 을 지운다' 는 하나의 동작으로 모입니다. 이 동작이 어떤 순서로, 얼마나 걸려, 메모리를 얼마나 잠깐 더 쓰는지 알아야 운영 계획을 세울 수 있습니다.
🏓 티티: 오늘의 표현은 "The Machine has been marked as unhealthy." 예요. 6단계에서 이벤트로 직접 보게 돼요. 고치는 건 MHC 가 아니라 소유자라는 것도 기억해요!
이 실습은 클러스터 준비(실측 3분 반에서 7분 반)와 교체 몇 번(각 1분에서 2분 반)을 기다립니다. 세션이 60분이니 연장이 필요할 수 있습니다. VM 이 끝나면 모두 사라집니다.
단계
- 2모듈에서 손으로 한 일(노드 이미지 받기 → generate → 템플릿 고치기 → apply → kubeconfig → Calico)을 묶은 도우미
capk-demo-up을systemd-run --unit=capk-demo-up으로 띄워 워크로드 클러스터capi-demo를 세우세요. 실측 3분 반에서 7분 반이 걸렸습니다(대부분 이미지 받기). 끝나면/root/capi/m3/capi-demo.kubeconfig가 생기고 노드 둘이 Ready 입니다. 기다리는 동안 이 모듈의 이론과 아래 단계를 읽어 두세요. - MachineDeployment
capi-demo-md-0의 replicas 를 2 로 늘리세요. 워커 Machine 둘이 Running 이고 워크로드 클러스터의 노드 셋이 모두 Ready 면 통과입니다(실측 51초). - 줄이기 전의 워커 Machine 이름을 기록한 뒤 replicas 를 1 로 줄이고,
/root/capi/m3/scaledown.json에before(줄이기 전 워커 이름 목록),after(줄인 뒤 워커 이름 목록),removed(사라진 Machine 이름)를 적으세요. 목록은 정렬합니다. - 남은 워커 Machine 하나를
kubectl delete machine으로 지우고, MachineSet 이 새 Machine 을 만들어 노드가 Ready 가 되는 것을 지켜보세요./root/capi/m3/replaced.json에deleted(지운 Machine 이름)와replacement(새로 생긴 Machine 이름)를 적습니다(실측 72초). - 워커를 지켜보는 MachineHealthCheck
capi-demo-md-0-mhc를/root/capi/m3/mhc.yaml로 쓰고 적용하세요. 대상은 라벨cluster.x-k8s.io/deployment-name=capi-demo-md-0인 Machine, 노드의Ready조건이False나Unknown으로 60초 이상 머물면 unhealthy 로 봅니다. 노드가 뜨기까지의 시한(nodeStartupTimeoutSeconds)은 600초입니다. 적용 뒤 MHC 의 status 에 지켜보는 Machine 수(expectedMachines)가 1 로 보이면 통과입니다. - 워커 노드가 죽은 상황을 흉내 내세요. 워커 Machine 과 같은 이름의 KubeVirt VM 을
runStrategy: Halted로 바꿔 멈추면 노드가 NotReady 가 되고, 60초 뒤 MachineHealthCheck 가 그 Machine 을 unhealthy 로 표시해 교체가 시작됩니다./root/capi/m3/remediation.json에victim(멈춘 Machine 이름)과replacement(교체로 새로 생긴 Machine 이름)를 적으세요. 새 노드가 Ready 면 통과입니다(실측 약 2분 반). - 워커의 vCPU 를 2개에서 1개로 줄이세요. 기존 KubevirtMachineTemplate
capi-demo-md-0을 고치지 말고, 그것을 복사해cpu.cores: 1인 새 템플릿capi-demo-md-1c을 만들고, MachineDeploymentcapi-demo-md-0의spec.template.spec.infrastructureRef.name을 그 이름으로 바꿉니다. 모든 워커 Machine 이 새 템플릿에서 복제된 것으로 바뀌고 노드가 Ready 면 통과입니다(실측 약 2분). - 7단계 변경을 리뷰받는다고 생각하고 영어 PR 설명을
/root/capi/m3/pr.md에 쓰세요. 정보를 채점합니다. 반드시 들어갈 것: 무엇을 왜 바꿨는지 밝히는 소제목 하나(What이나Why나Summary가 든 제목), 어떻게 확인했는지 밝히는 소제목 하나(Test나Verif가 든 제목), 두 템플릿 이름capi-demo-md-0와capi-demo-md-1c,MachineDeployment, 확인에 쓴 명령kubectl get machines. 그리고Reply to review가 든 소제목 아래에 리뷰어 질문 "Why not just editcapi-demo-md-0in place?" 에 대한 답을 쓰되, 템플릿이 바뀌지 않는다는 뜻의immutable이나 교체 방식을 말하는rollout(또는roll out)을 넣으세요. 영어로 80단어 이상.
참고
- 관리 클러스터는 init 까지 되어 있고, 도우미
capk-demo-up이 2모듈의 일을 한 번에 합니다. 워크로드 클러스터 kubeconfig 는/root/capi/m3/capi-demo.kubeconfig입니다. - 메모리 예산: 이 VM(8 GiB)에서 컨트롤 플레인 2Gi + 워커 1Gi 둘이면 남는 것이 약 1GiB 입니다. 워커를 셋 이상 늘리거나 템플릿 메모리를 키우면 새 노드가
Insufficient memory로 Pending 에 머뭅니다. - 흔한 실수: MHC 를 걸어 둔 채 일부러 노드를 멈추고, 교체가 늦다고 Machine 을 손으로 지우는 것. MHC 는 timeoutSeconds 를 기다린 뒤 표시합니다. 60초에 노드가 NotReady 가 되는 시간(약 40초)이 더해집니다.
- 흔한 실수: 옛 템플릿을 고쳐 롤링을 기대하는 것. CAPK 웹훅이
KubevirtMachineTemplateSpec is immutable로 거부하고(실측), 롤링의 신호는 MachineDeployment 가 가리키는 이름의 변화입니다. - 문서: MachineHealthCheck · Scaling nodes · Changing a Machine template
Spin up the demo cluster
2모듈에서 손으로 한 일(노드 이미지 받기 → generate → 템플릿 고치기 → apply → kubeconfig → Calico)을 묶은 도우미 capk-demo-up 을 systemd-run --unit=capk-demo-up 으로 띄워 워크로드 클러스터 capi-demo 를 세우세요. 실측 3분 반에서 7분 반이 걸렸습니다(대부분 이미지 받기). 끝나면 /root/capi/m3/capi-demo.kubeconfig 가 생기고 노드 둘이 Ready 입니다. 기다리는 동안 이 모듈의 이론과 아래 단계를 읽어 두세요.
도우미는 /usr/local/bin/capk-demo-up 에 있는 셸 스크립트라 cat 으로 읽을 수 있습니다. 로그는 /root/capi/m3/demo-up.log 에 남기게 하고(bash -c '... > log 2>&1'), systemctl status capk-demo-up 과 kubectl get machines -w 로 지켜봅니다. 이미지 받기가 시간의 절반 이상입니다.
Scale out to two workers
MachineDeployment capi-demo-md-0 의 replicas 를 2 로 늘리세요. 워커 Machine 둘이 Running 이고 워크로드 클러스터의 노드 셋이 모두 Ready 면 통과입니다(실측 51초).
MachineDeployment 는 Deployment 처럼 scale 하위 자원이 있어 kubectl scale 이 됩니다. 늘린 Machine 은 같은 템플릿에서 복제되므로 이름 앞부분(MachineSet 이름)이 같습니다. 워커 둘이면 이 VM 의 남은 메모리가 약 1GiB 로 줄어드니 셋 이상은 늘리지 마세요.
Scale back in, and record who left
줄이기 전의 워커 Machine 이름을 기록한 뒤 replicas 를 1 로 줄이고, /root/capi/m3/scaledown.json 에 before(줄이기 전 워커 이름 목록), after(줄인 뒤 워커 이름 목록), removed(사라진 Machine 이름)를 적으세요. 목록은 정렬합니다.
MachineSet 은 줄일 때 어느 Machine 을 지울지 deletion order(기본 Random)로 고릅니다. 그래서 줄이기 전에 이름을 적어 두지 않으면 누가 사라졌는지 나중에 알기 어렵습니다. kubectl get machines -l cluster.x-k8s.io/deployment-name=capi-demo-md-0 로 워커만 골라 볼 수 있습니다.
Delete a Machine, get a new one
남은 워커 Machine 하나를 kubectl delete machine 으로 지우고, MachineSet 이 새 Machine 을 만들어 노드가 Ready 가 되는 것을 지켜보세요. /root/capi/m3/replaced.json 에 deleted(지운 Machine 이름)와 replacement(새로 생긴 Machine 이름)를 적습니다(실측 72초).
Machine 을 지우면 Cluster API 는 노드를 drain 하고 VM 을 지운 뒤 Machine 을 없앱니다. MachineSet 은 replicas 1 을 지키려고 곧바로 새 Machine 을 만듭니다. 노드를 고치는 대신 바꾸는(replace) 것이 Cluster API 의 기본 태도입니다. 지우기 전 이름을 먼저 적어 두세요.
Add a MachineHealthCheck
워커를 지켜보는 MachineHealthCheck capi-demo-md-0-mhc 를 /root/capi/m3/mhc.yaml 로 쓰고 적용하세요. 대상은 라벨 cluster.x-k8s.io/deployment-name=capi-demo-md-0 인 Machine, 노드의 Ready 조건이 False 나 Unknown 으로 60초 이상 머물면 unhealthy 로 봅니다. 노드가 뜨기까지의 시한(nodeStartupTimeoutSeconds)은 600초입니다. 적용 뒤 MHC 의 status 에 지켜보는 Machine 수(expectedMachines)가 1 로 보이면 통과입니다.
CAPI v1.14 가 저장하는 판은 cluster.x-k8s.io/v1beta2 이고, 이 판에서는 검사 규칙이 spec.checks 아래 unhealthyNodeConditions(type·status·timeoutSeconds)와 nodeStartupTimeoutSeconds 로 모였습니다. 모르는 필드는 kubectl explain machinehealthcheck.spec.checks --api-version=cluster.x-k8s.io/v1beta2 로 찾습니다. MHC 는 고치지 않습니다. unhealthy 라고 표시하면 소유자(MachineSet)가 지우고 새로 만듭니다.
Break a node and let it heal
워커 노드가 죽은 상황을 흉내 내세요. 워커 Machine 과 같은 이름의 KubeVirt VM 을 runStrategy: Halted 로 바꿔 멈추면 노드가 NotReady 가 되고, 60초 뒤 MachineHealthCheck 가 그 Machine 을 unhealthy 로 표시해 교체가 시작됩니다. /root/capi/m3/remediation.json 에 victim(멈춘 Machine 이름)과 replacement(교체로 새로 생긴 Machine 이름)를 적으세요. 새 노드가 Ready 면 통과입니다(실측 약 2분 반).
VM 을 지우면 CAPK 가 그것을 다시 만들 수 있지만, 멈추면(Halted) 그대로 꺼진 채 남습니다. 노드는 kubelet 신호가 끊기고 약 40초 뒤 NotReady(Unknown)가 됩니다. kubectl get events --field-selector reason=MachineMarkedUnhealthy 와 kubectl get mhc -w 로 표시와 교체를 지켜보세요. 멈추기 전에 victim 이름을 적어 두면 편합니다.
Roll out a new worker template
워커의 vCPU 를 2개에서 1개로 줄이세요. 기존 KubevirtMachineTemplate capi-demo-md-0 을 고치지 말고, 그것을 복사해 cpu.cores: 1 인 새 템플릿 capi-demo-md-1c 을 만들고, MachineDeployment capi-demo-md-0 의 spec.template.spec.infrastructureRef.name 을 그 이름으로 바꿉니다. 모든 워커 Machine 이 새 템플릿에서 복제된 것으로 바뀌고 노드가 Ready 면 통과입니다(실측 약 2분).
인프라 템플릿은 바꾸지 않는다(immutable)는 것이 Cluster API 의 약속이고, CAPK 는 그 자리에서 고치려는 요청을 웹훅으로 거부합니다. 같은 이름의 템플릿 내용이 바뀌면 어느 Machine 이 옛 내용이고 어느 것이 새 내용인지 알 수 없기 때문입니다. 새 이름의 템플릿을 만들고 MachineDeployment 가 그것을 가리키게 하면, MachineDeployment 가 새 MachineSet 을 만들어 maxSurge 1 로 하나씩 교체합니다. Machine 이 어느 템플릿에서 왔는지는 그 KubevirtMachine 의 cluster.x-k8s.io/cloned-from-name 어노테이션이 알려 줍니다.
Describe the change in a PR
7단계 변경을 리뷰받는다고 생각하고 영어 PR 설명을 /root/capi/m3/pr.md 에 쓰세요. 정보를 채점합니다. 반드시 들어갈 것: 무엇을 왜 바꿨는지 밝히는 소제목 하나(What 이나 Why 나 Summary 가 든 제목), 어떻게 확인했는지 밝히는 소제목 하나(Test 나 Verif 가 든 제목), 두 템플릿 이름 capi-demo-md-0 와 capi-demo-md-1c, MachineDeployment, 확인에 쓴 명령 kubectl get machines. 그리고 Reply to review 가 든 소제목 아래에 리뷰어 질문 "Why not just edit capi-demo-md-0 in place?" 에 대한 답을 쓰되, 템플릿이 바뀌지 않는다는 뜻의 immutable 이나 교체 방식을 말하는 rollout(또는 roll out)을 넣으세요. 영어로 80단어 이상.
PR 설명은 리뷰어가 코드를 열기 전에 읽는 요약입니다. What(무엇을)과 Why(왜) 다음에 How it was tested(어떻게 확인했나)를 두면, 리뷰어가 '이걸 어떻게 확인했어요?' 를 묻지 않아도 됩니다. 리뷰 답글은 질문을 다시 말하지 말고 결론부터, 근거를 한 문장으로 붙입니다. 블로그 「오늘의 영어 표현」의 「No functional change」 편(/blog/english-daily-08-no-functional-change) 와 「Addressed in commit」 편(/blog/english-daily-17-addressed-in-commit)에 예문이 더 있습니다.